Python: ¿datos vs. texto?

La presentación de Guido van Rossum sobre Python 3000 menciona varias cosas para hacer que la transición de Python 2 a Python 3 sea más fácil con el tiempo. Está hablando específicamente sobre el manejo de texto desde que el cambio a Unicode como la única representación de cadenas en Python 3 es uno de los cambios principales.

En cuanto al manejo del texto, una diapositiva (n. ° 14) dice:

  • En 2.6:
    • Use bytes y b ‘…’ para todos los datos (Sabiendo que estos son solo alias para str y ‘…’)
    • Use unicode yu ‘…’ para todo el texto
  • En 2.5:
    • ‘…’ para datos, u ‘…’ para texto

Estoy usando Python 2.6.4. ¿Qué significa esto exactamente para mí?

En el mundo de Python, ¿cuál es la diferencia entre datos y texto?

En pocas palabras, la forma en que se maneja el texto y los datos en Py3k podría ser el cambio más “importante” en el idioma. Al conocer y evitar, cuando sea posible, las situaciones en las que alguna lógica de Python 2.6 funcionará de manera diferente que en 3.x, podemos facilitar la migración cuando suceda. Sin embargo, debemos esperar que algunas partes de la lógica 2.6 requieran atención especial y modificaciones, por ejemplo, para tratar con distintas codificaciones, etc.

La idea detrás de la sugerencia de BDFL en la diapositiva 14 es probablemente comenzar a ” usar ” los mismos tipos que Py3k admite (y solo estos), a saber, cadenas de Unicode para cadenas (tipo str ) y secuencias de bytes de 8 bits para “datos” (tipo de bytes ) .

El término ” usar ” en la oración anterior se usa de forma bastante imprecisa ya que la semántica y el almacenamiento / encoding asociado para estos tipos difiere entre las versiones 2.6 y 3.x. En Python 2.6, el tipo de bytes y la syntax literal asociada (b’xyz ‘) simplemente se asignan al tipo str. Por lo tanto

 # in Py2.6 >>'mykey' == b'mykey' True b'mykey'.__class__  # in Py3k >>>'mykey' == b'mykey' False b'mykey'.__class__  

Para responder a su pregunta [en los comentarios a continuación], en 2.6, si usa b’xyz ‘o’ xyz ‘, Python lo entiende como lo mismo y una cosa: una str. Lo que es importante es que entiendas esto como [potencialmente / en el futuro] dos tipos distintos con un propósito distinto :

  • Str para información similar a texto, y
  • Bytes para secuencias de octetos que almacenan cualquier dato disponible.

Por ejemplo, nuevamente hablando cerca de su ejemplo / pregunta, en Py3k podrá tener un diccionario con dos elementos que tienen una clave similar, uno con b’mykey ‘y el otro con’ mykey ‘, sin embargo, bajo 2.6 esto no es posible, ya que estas dos claves son realmente iguales; lo que importa es que sepa este tipo de cosas y evite (o marque explícitamente de una manera especial en el código) las situaciones donde el código 2.6 no funcionará en 3.x.

En Py3k, str es una cadena abstracta de Unicode, una secuencia de puntos de código Unicode (caracteres) y Python trata de convertir esto a / desde su forma codificada, cualquiera que sea la encoding (como progtwigdor, usted tiene algo que decir sobre la encoding pero la hora en que se ocupa de las operaciones de cadena y no necesita preocuparse por estos detalles). En contraste, los bytes son una secuencia de “cosas” de 8 bits que la semántica y la encoding quedan totalmente en manos del progtwigdor.

Entonces, a pesar de que Python 2.6 no ve una diferencia, al usar explícitamente bytes () / b ‘…’ o str () / u ‘…’, usted …

  • … prepárese y prepare su progtwig para los próximos tipos y semánticas de Py3k
  • … facilite la conversión automática (herramienta 2to3 u otra) del código fuente, por lo que la b en b ‘…’ permanecerá y la u de u ‘…’ se eliminará (ya que la única el tipo de cadena será unicode).

Para más información :
Python 2.6 Novedades (ver PEP 3112 Bytes Literales)
Novedades de Python 3.0 (ver Text Vs. Data Instead Of Unicode Vs. 8-bit cerca de la parte superior)

La respuesta a su primera pregunta es simple: en Python 2.6, puede hacerlo como solía hacerlo. Pero, si lo desea, puede cambiar a los estándares Py3k escribiendo:

 from __future__ import unicode_literals 

Su segunda pregunta necesita más aclaración:

Las cadenas son datos que se imprimen como personajes humanos. No solo en Python, sino que cada idioma (que conozco) tiene su camino cuando se trata de cadenas.

Sin embargo, los fundamentos comunes son las codificaciones. Las codificaciones son la forma de asignar secuencias de bytes a glifos (es decir, en su mayoría símbolos imprimibles).

Python ofrece una forma sencilla de superar las complejidades de administrar codificaciones (cuando pones literales de cadena en tu código).

Veamos un ejemplo muy simple:

 >>> len("Mañana") 7 

Sólo veo 6 símbolos. Así que espero que len hubiera regresado 6. ¿De dónde viene este “símbolo” adicional? Bueno, en UTF-8 el símbolo ñ se representa con 2 bytes. Antes de Py3k, los literales de cadena son solo secuencias de bytes. Entonces, Python ve esa cadena como bytes y los cuenta a todos: Ma\xc3\xb1ana .

Sin embargo, si ejecuto lo siguiente:

 >>> len(u"Mañana") 6 

Entonces, Python “sabe” exactamente que las secuencias de 2 bytes para “ñ” deben considerarse como una sola letra.

Esto de ninguna manera es exclusivo de Python. El siguiente script PHP muestra el mismo comportamiento:

 manu@pavla:~$ php < EOF 7 

La solución PHP pasa a ser más elaborada:

 manu@pavla:~$ php < EOF 6 

Tenga en cuenta que debo sustituir mb_strlen por strlen y debo pasar utf-8 (la encoding) como segundo argumento.

Una advertencia: las cadenas proporcionadas por el usuario generalmente vienen como bytes, no como cadenas Unicode. Así que tienes que cuidar de eso. Ver más en http://mail.python.org/pipermail/python-list/2008-July/139193.html