Pregunta

Ya tenemos nuestra base de código ejecutándose en Python 2.6. Para prepararnos para Python 3.0, hemos comenzado a agregar:

from __future__ import unicode_literals

en nuestros archivos .py (a medida que los modificamos). Me pregunto si alguien más ha estado haciendo esto y se ha topado con alguna trampa no obvia (tal vez después de pasar mucho tiempo depurando).

¿Fue útil?

Solución

La principal fuente de problemas que he tenido al trabajar con cadenas Unicode es cuando se mezclan cadenas codificadas utf-8 con cadenas Unicode.

Por ejemplo, considere los siguientes scripts.

two.py

# encoding: utf-8
name = 'helló wörld from two'

one.py

# encoding: utf-8
from __future__ import unicode_literals
import two
name = 'helló wörld from one'
print name + two.name

El resultado de ejecutar python one.py es:

Traceback (most recent call last):
  File "one.py", line 5, in <module>
    print name + two.name
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)

En este ejemplo, two.name es una cadena codificada utf-8 (no unicode) ya que no importó unicode_literals y one.name es una cadena unicode. Cuando mezcla ambos, python intenta decodificar la cadena codificada (suponiendo que sea ascii) y convertirla a unicode y falla. Funcionaría si hiciera print name + two.name.decode ('utf-8') .

Lo mismo puede suceder si codifica una cadena e intenta mezclarla más tarde. Por ejemplo, esto funciona:

# encoding: utf-8
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
    html = html.encode('utf-8')
print 'DEBUG: %s' % html

Salida:

DEBUG: <html><body>helló wörld</body></html>

Pero después de agregar el import unicode_literals NO:

# encoding: utf-8
from __future__ import unicode_literals
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
    html = html.encode('utf-8')
print 'DEBUG: %s' % html

Salida:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    print 'DEBUG: %s' % html
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 16: ordinal not in range(128)

Falla porque 'DEBUG:% s' es una cadena unicode y, por lo tanto, python intenta decodificar html . Hay un par de formas de arreglar la impresión haciendo print str ('DEBUG:% s')% html o print 'DEBUG:% s'% html.decode ('utf-8 ') .

Espero que esto le ayude a comprender las posibles trampas al usar cadenas Unicode.

Otros consejos

También en 2.6 (antes de python 2.6.5 RC1 +) los literales unicode no funcionan bien con argumentos de palabras clave ( issue4978 ):

El siguiente código, por ejemplo, funciona sin unicode_literals, pero falla con TypeError: las palabras clave deben ser cadena si se usa unicode_literals.

  >>> def foo(a=None): pass
  ...
  >>> foo(**{'a':1})
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
      TypeError: foo() keywords must be strings

Encontré que si agrega la directiva unicode_literals también debe agregar algo como:

 # -*- coding: utf-8

a la primera o segunda línea de su archivo .py. De lo contrario, líneas como:

 foo = "barré"

produce un error como:

SyntaxError: Non-ASCII character '\xc3' in file mumble.py on line 198,
 but no encoding declared; see http://www.python.org/peps/pep-0263.html 
 for details

También tenga en cuenta que unicode_literal afectará a eval () pero no a repr () (un comportamiento asimétrico que es un error) , es decir, eval (repr (b '\ xa4')) no será igual a b '\ xa4' (como lo haría con Python 3).

Idealmente, el siguiente código sería un invariante, que siempre debería funcionar, para todas las combinaciones de unicode_literals y Python {2.7, 3.x} uso:

from __future__ import unicode_literals

bstr = b'\xa4'
assert eval(repr(bstr)) == bstr # fails in Python 2.7, holds in 3.1+

ustr = '\xa4'
assert eval(repr(ustr)) == ustr # holds in Python 2.7 and 3.1+

La segunda aserción funciona, ya que repr ('\ xa4') se evalúa como u '\ xa4' en Python 2.7.

Hay más.

Hay bibliotecas y componentes integrados que esperan cadenas que no toleran unicode.

Dos ejemplos:

incorporado:

myenum = type('Enum', (), enum)

(ligeramente esótico) no funciona con unicode_literals: type () espera una cadena.

biblioteca:

from wx.lib.pubsub import pub
pub.sendMessage("LOG MESSAGE", msg="no go for unicode literals")

no funciona: la biblioteca wx pubsub espera un tipo de mensaje de cadena.

El primero es esotérico y se arregla fácilmente con

myenum = type(b'Enum', (), enum)

pero este último es devastador si su código está lleno de llamadas a pub.sendMessage () (que es el mío).

¡Maldita sea, eh?!?

El clic generará excepciones unicode en todo el lugar si algún módulo que tiene de __future__ import unicode_literals se importa donde utiliza click.echo . Es una pesadilla & # 8230;

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top