2010-12-27 15 views
22

perdone si esta mucho una pregunta:Python y Unicode: ¿Cómo debería ser todo lo Unicode

he estado programando en Python por alrededor de seis meses. Autodidacta, comenzando con el tutorial de Python y luego SO y luego usando Google para cosas.

Aquí está la parte triste: Nadie me dijo que todas las cadenas deberían ser Unicode. No, no estoy mintiendo ni inventando esto, pero ¿dónde lo menciona el tutorial? Y la mayoría de los ejemplos también veo simplemente hacer uso de byte strings, en lugar de Unicode strings. Estaba navegando y encontré esta pregunta en SO, que dice cómo cada cadena en Python debe ser una cadena Unicode. ¡Esto me hizo llorar!

leí que cada cadena en Python 3.0 es Unicode por defecto, así que mis preguntas son para 2.x:

  1. debo hacer una:

    print u'Some text' o simplemente print 'Text'?

  2. Todo debe estar Unicode, significa esto, al igual que decir que tengo un tuple:

    t = ('First', 'Second'), it should be t = (u'First', u'Second')?

    leí que puedo hacer un from __future__ import unicode_literals y luego cada cadena será una cadena Unicode, sino que debe Hago esto dentro de un contenedor también?

  3. Al leer/escribir en un archivo, debo usar el módulo codecs. ¿Derecha? ¿O debería usar el modo estándar o leer/escribir y encode o decode cuando sea necesario?

  4. Si obtengo la cadena de, por ejemplo, raw_input(), ¿debo convertir eso a Unicode también?

¿Cuál es el enfoque común para manejar todos los problemas anteriores en 2.x? ¿La declaración from __future__ import unicode_literals?

Disculpa por ser una novata, pero esto cambia lo que he estado haciendo durante mucho tiempo y estoy tan confundido.

+1

¿Por qué no utilizar Python 3 y avanzar con los tiempos? –

+17

Casi todas las distribuciones de Linux todavía vienen con 2x. No hay nada de malo en escribir programas 2x. Ahí es donde también está la gran mayoría de las bibliotecas. – Falmarri

+3

Nitpick: 'from __future__ import unicode_literals', plural. –

Respuesta

14

La sugerencia de "utilizar siempre Unicode" es principalmente para facilitar la transición a Python 3. Si tiene una gran cantidad de acceso a cadenas que no son Unicode en su código, le llevará más trabajo portarlo.

Además, no debería tener que decidir, caso por caso, si una cadena debe almacenarse como Unicode o no. No debería tener que cambiar los tipos de sus cadenas y su propia sintaxis simplemente porque cambió sus contenidos, tampoco.

También es fácil utilizar el tipo de cadena incorrecto, lo que lleva al código que funciona mayoritariamente, o código que funciona en Linux pero no en Windows, o en una configuración regional pero no en otra. Por ejemplo, for c in "漢字" en una configuración regional UTF-8 iterará sobre cada byte UTF-8 (los seis), no sobre cada carácter; si eso rompe las cosas depende de lo que hagas con ellos.

En principio, nada debería romperse si usa cadenas Unicode, pero las cosas pueden romperse si usa cadenas normales cuando no debería.

En la práctica, sin embargo, es un dolor usar cadenas Unicode en todas partes en Python 2. codecs.open no elige la configuración regional correcta automáticamente; esto falla:

codecs.open("blar.txt", "w").write(u"漢字") 

La verdadera respuesta es:

import locale, codecs 
lang, encoding = locale.getdefaultlocale() 
codecs.open("blar.txt", "w", encoding).write(u"漢字") 

... lo cual es engorroso, obligando a la gente a realizar funciones de ayuda sólo para abrir archivos. codecs.opendebe utilizar la codificación de locale automáticamente cuando no se especifica; La falla de Python en hacer que una operación tan simple sea conveniente es una de las razones por las cuales las personas generalmente no usan usan Unicode en todas partes.

Finalmente, tenga en cuenta que las cadenas Unicode son incluso más críticas en Windows en algunos casos. Por ejemplo, si se encuentra en una configuración regional occidental y tiene un archivo llamado "漢字", debe utilizar una cadena Unicode para acceder a ella, por ej. os.stat(u"漢字"). Es imposible acceder a ella con una cadena no Unicode; simplemente no verá el archivo.

Así que, en principio, diría que la recomendación de la cadena Unicode es razonable, pero con la advertencia de que generalmente ni siquiera la sigo.

+1

Borras muchas cosas, entonces +1. Especialmente la parte local ayudó. – user225312

+0

¿No usará la declaración 'from __future__' para borrar todo? ¿O es simplemente malo? – user225312

+1

No cambiará el comportamiento de 'codecs.open'. –

-2

1/2) Personalmente, nunca he oído hablar de "utilizar siempre unicode". Eso me parece bastante estúpido. Supongo que entiendo si planea soportar otros idiomas que necesitan soporte Unicode. Pero aparte de eso, no haría eso, parece más doloroso de lo que vale.

3) Solo leería/escribiría de la manera estándar y codificaría cuando fuera necesario.

+2

Bueno, basé 'siempre uso Unicode' sobre la base del enlace que publiqué en mi pregunta. Si Google 'Python Unicode', encontrará lo mismo. – user225312

2

El hecho de que estuviera escribiendo código Python durante 6 meses antes de encontrar algo sobre Unicode significa que el valor predeterminado ASCII de Python 2.x para cadenas no le causó ningún problema. Ciertamente, para un principiante tratar de captar la idea de puntos/codificación de Unicode/código en sí mismo es un problema difícil de abordar; por lo tanto, la mayoría de los tutoriales, naturalmente, pasan por alto hasta que obtenga más de una base en los fundamentos. Es por eso que en un libro como Dive Into Python, Unicode solo se menciona in later chapters.

Si necesita admitir Unicode en su aplicación, le sugiero consultar Kumar McMillan's PyCon 2008 talk on Unicode para obtener una lista de las mejores prácticas. Debería responder a sus preguntas restantes.

+0

La charla parece interesante, gracias, lo voy a ver. – user225312

+3

No le causó problemas porque los programadores principiantes generalmente no implementan cosas como la internacionalización, y no se preocupan por los problemas que estarían causando a otros si lanzan un programa sin soporte Unicode, especialmente en Windows. –

+0

@Glenn: Eso es cierto. – user225312

11

No, no todas las cadenas "deben ser Unicode". Dentro de su código de Python, usted sabe si los literales de cadena deben ser Unicode o no, por lo que no tiene ningún sentido convertir cada cadena literal en un literal Unicode.

Pero hay casos en los que debe usar Unicode. Por ejemplo, si tiene una entrada arbitraria que es texto, use Unicode para ello. Más tarde o más temprano, encontrará que un no estadounidense lo usa, y desea escribir lo que está diciendo. Y obtendrá problemas en ese caso a menos que su entrada y salida utilicen la misma codificación, de la que no puede estar seguro.

En resumen, no, cadenas no debe ser Unicode. El texto debería ser. Pero YMMV.

Específicamente:

  1. No hay necesidad de utilizar Unicode aquí. Usted sabe si esa cadena es ASCII o no.

  2. Depende si necesita unir esas cadenas con Unicode o no.

  3. Ambas formas funcionan. Pero no codifique la decodificación "cuando sea necesario". Decodifica ASAP, codifica lo más tarde posible. El uso de códecs funciona bien (o io, desde Python 2.7).

  4. Sí.

+1

Una respuesta interesante, pero no pude obtener un punto: Mencionas que 'cadenas 'no debería ser Unicode, mientras que' text' debería ser. ¿Cuál es la distinción? – user225312

+0

@AAI creo que se refería al texto como cadenas mostradas en la consola, el navegador, guardado en archivos, bases de datos, etc. – marcog

+0

@AA: texto frente a datos lea esto: http://docs.python.org/release/3.0.1/ whatsnew/3.0.html # text-vs-data-instead-of-unicode-vs-8-bit – mouad

6

mi humilde opinión (mis reglas simples):

  1. debo hacer una: print u'Some text' or just print 'Text'?

  2. Todo debe ser Unicode, ¿quiere decir esto, como decir que tengo una tupla: t = ('First', 'Second'), it should be t = (u'First', u'Second')?

Bueno, utilizar literales Unicode sólo cuando tengo algo de carbón por encima de ASCII 128:

print 'New York', u'São Paulo' 
    t = ('New York', u'São Paulo') 
  1. Al leer/escribir en un archivo, debería utilizar el módulo de códecs . ¿Derecha? ¿O debería usar el modo estándar o leer/escribir y codificar o decodificar cuando sea necesario?

Si espera texto unicode, use los códecs.

  1. Si consigo la cadena de decir raw_input(), debo convertir a Unicode que también?

Sólo si espera que el texto Unicode que puedan quedar transferido a otro sistema con distinta codificación predeterminada (incluyendo bases de datos).

editada (en mezclar Unicode y cadenas de bytes):

>>> print 'New York', 'to', u'São Paulo' 
New York to São Paulo 
>>> print 'New York' + ' to ' + u'São Paulo' 
New York to São Paulo 
>>> print "Côte d'Azur" + ' to ' + u'São Paulo' 
Traceback (most recent call last): 
    File "<interactive input>", line 1, in <module> 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: 
    ordinal not in range(128) 
>>> print "Côte d'Azur".decode('utf-8') + ' to ' + u'São Paulo' 
Côte d'Azur to São Paulo 

Así que si se mezclan una serie de bytes que contiene UTF-8 (u otro carbón no ASCII) con el texto Unicode sin necesidad de conversión explícita, tendrá problema, porque por defecto ascii ascii. El otro lado parece ser seguro. Si sigues la regla de escribir cada cadena que contiene no-ascii como un literal unicode, deberías estar bien.

DESCARGO DE RESPONSABILIDAD: Yo vivo en Brasil, donde la gente habla portugués, un idioma con muchos caracteres no ascii. Mi codificación predeterminada siempre está configurada en 'utf-8'. Su millaje puede variar en inglés/ascii sistemas.

+0

Responde perfectamente la 2da pregunta. – user225312

+0

¿Pero no sería una mezcla de cadenas de bytes y unicode causar problemas? – user225312

+1

Bueno, si mezcla una cadena de bytes que contiene utf-8 (u otro carácter no explícito) con texto Unicode sin conversión explícita, tendrá problemas, ya que ascii por defecto ascii. –

3

Solo estoy agregando mi opinión personal aquí. No es tan largo y elaborado en las otras respuestas, pero tal vez puede ayudar también.

print u'Some text' o simplemente print 'Text'?

Preferiría la primera. Si sabes que solo tienes cadenas Unicode, tienes una invariante más. Varios otros lenguajes (C, C++, Perl, PHP, Ruby, Lua, ...) a veces encuentran problemas dolorosos debido a su falta de separación entre secuencias de unidades de código y secuencias enteras. El enfoque de la distinción estricta entre ellos que existe en .NET, Java, Python, etc. es bastante más limpio.

Todo debe estar Unicode, significa esto, al igual que decir que tengo una tupla:

t = ('First', 'Second'), debería ser t = (u'First', u'Second')?

Sí.

He leído que puedo hacer un from __future__ import unicode_literals y luego cada cadena será una cadena Unicode, pero ¿debo hacer esto también dentro de un contenedor?

Sí. Las declaraciones futuras se aplican solo al archivo donde se usan, por lo que puede usarlas sin interferir con otros módulos. Generalmente importo todos los futuros en los módulos de Python 2.x para facilitar la transición a 3.x.

Al leer/escribir en un archivo, debo usar el módulo codecs. ¿Derecha? ¿O debería usar el modo estándar o leer/escribir y codificar o decodificar cuando sea necesario?

debería utilizar el módulo de codecs porque eso hace que sea imposible (o al menos muy difícil) para escribir accidentalmente representaciones codificadas de manera diferente a un solo archivo. También es la forma en que funciona Python 3.x cuando abre un archivo en modo texto.

Si obtengo la cadena de decir raw_input(), ¿debo convertir eso a Unicode también?

Yo diría que sí a esto también: en la mayoría de los casos es más fácil tratar con una sola codificación, por lo que recomiendo convertir cadenas Python Unicode lo antes posible.

¿Cuál es el enfoque común para manejar todos los problemas anteriores en 2.x? ¿La declaración from __future__ import unicode_literals?

No sé cuál es el enfoque común, pero uso esa afirmación todo el tiempo. He encontrado muy pocos problemas con este enfoque, y la mayoría de ellos están relacionados con errores en bibliotecas externas, es decir, NumPy a veces requiere cadenas de bytes sin documentar eso.