La principal fuente de problemas que he tenido al trabajar con cadenas Unicode es cuando se mezclan cadenas codificadas en 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 correr 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 en utf-8 (no unicode) ya que no se importó unicode_literals
, y one.name
es una cadena unicode. Cuando mezcla ambos, Python intenta decodificar la cadena codificada (asumiendo que es ascii) y convertirla a Unicode y falla. Funcionaría si lo hicieras print name + two.name.decode('utf-8')
.
Lo mismo puede suceder si codifica una cadena e intenta mezclarlos 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
. Un par de formas de arreglar la impresión son 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.
decode()
soluciones en lugar de las solucionesstr()
oencode()
: cuanto más a menudo use objetos Unicode, más claro será el código, ya que lo que desea es manipular cadenas de caracteres, no matrices de bytes con una codificación implícita externamente.when you mix utf-8 encoded strings with unicode ones
UTF-8 y Unicode no son 2 codificaciones diferentes; Unicode es un estándar y UTF-8 es una de las codificaciones que define.str
, el segundo es de tipounicode
. Al ser objetos diferentes, pueden surgir problemas si intentapython>=2.6
opython==2.6
?También en 2.6 (antes de python 2.6.5 RC1 +), los literales Unicode no funcionan bien con los argumentos de palabras clave ( problema4978 ):
El siguiente código, por ejemplo, funciona sin unicode_literals, pero falla con TypeError:
keywords must be string
si se usa unicode_literals.fuente
Descubrí que si agrega la
unicode_literals
directiva, también debe agregar algo como:a la primera o segunda línea de su archivo .py. De lo contrario, líneas como:
dar como resultado un error como:
fuente
# -*- coding: utf-8
es una declaración prácticamente obligatoria, independientemente de si la usaunicode_literals
o no-*-
es obligatorio; si optara por el método compatible con emacs, creo que lo necesitaría-*- encoding: utf-8 -*-
(consulte-*-
también al final). Todo lo que necesitas escoding: utf-8
(o incluso en=
lugar de:
).from __future__ import unicode_literals
.# -*- coding: utf-8 -*-
"codificación" (no "codificación" o "codificación de archivos" o cualquier otra cosa; Python solo busca "codificación" independientemente de cualquier prefijo).También tenga en cuenta que
unicode_literal
afectaráeval()
pero norepr()
(un comportamiento asimétrico que en mi humilde opinión es un error), es decireval(repr(b'\xa4'))
, no será igual ab'\xa4'
(como lo haría con Python 3).Idealmente, el siguiente código sería invariante, que siempre debería funcionar, para todas las combinaciones
unicode_literals
y el uso de Python {2.7, 3.x}:La segunda afirmación funciona, ya que se
repr('\xa4')
evalúau'\xa4'
en Python 2.7.fuente
repr
para regenerar un objeto. Larepr
documentación establece claramente que esto no es un requisito. En mi opinión, esto lo relegarepr
a algo útil solo para depurar.Hay mas.
Hay bibliotecas y archivos incorporados que esperan cadenas que no toleran unicode.
Dos ejemplos:
incorporado:
(ligeramente esótico) no funciona con unicode_literals: type () espera una cadena.
biblioteca:
no funciona: la biblioteca wx pubsub espera un tipo de mensaje de cadena.
El primero es esotérico y se arregla fácilmente con
pero este último es devastador si su código está lleno de llamadas a pub.sendMessage () (que es el mío).
Maldita sea, ¿eh?!?
fuente
class Meta:
debe serb'field_name'
El clic generará excepciones Unicode en todo el lugar si
from __future__ import unicode_literals
se importa algún módulo que tenga en el lugar donde lo usaclick.echo
. Es una pesadilla…fuente