tl; dr / solución rápida
- No decodifique / codifique willy nilly
- No asuma que sus cadenas están codificadas en UTF-8
- Intente convertir cadenas en cadenas Unicode lo antes posible en su código
- Repara tu configuración regional: ¿Cómo resolver UnicodeDecodeError en Python 3.6?
- No caigas en la tentación de usar
reload
hacks rápidos
Unicode Zen en Python 2.x - La versión larga
Sin ver la fuente, es difícil conocer la causa raíz, por lo que tendré que hablar en general.
UnicodeDecodeError: 'ascii' codec can't decode byte
generalmente ocurre cuando intenta convertir un Python 2.x str
que contiene no ASCII a una cadena Unicode sin especificar la codificación de la cadena original.
En resumen, las cadenas Unicode son un tipo completamente separado de cadena Python que no contiene ninguna codificación. Solo contienen códigos de punto Unicode y, por lo tanto, pueden contener cualquier punto Unicode de todo el espectro. Las cadenas contienen texto codificado, como UTF-8, UTF-16, ISO-8895-1, GBK, Big5, etc. Las cadenas se decodifican en Unicode y los Unicodes se codifican en cadenas . Los archivos y los datos de texto siempre se transfieren en cadenas codificadas.
Los autores del módulo Markdown probablemente usan unicode()
(donde se lanza la excepción) como una puerta de calidad para el resto del código: convertirá ASCII o volverá a envolver las cadenas Unicodes existentes en una nueva cadena Unicode. Los autores de Markdown no pueden conocer la codificación de la cadena entrante, por lo que confiarán en usted para decodificar cadenas en cadenas Unicode antes de pasar a Markdown.
Las cadenas Unicode se pueden declarar en su código utilizando el u
prefijo a las cadenas. P.ej
>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>
Las cadenas Unicode también pueden provenir de archivos, bases de datos y módulos de red. Cuando esto sucede, no necesita preocuparse por la codificación.
Gotchas
La conversión de str
a Unicode puede ocurrir incluso cuando no llama explícitamente unicode()
.
Los siguientes escenarios causan UnicodeDecodeError
excepciones:
# Explicit conversion without encoding
unicode('€')
# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')
# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'
# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'
Ejemplos
En el siguiente diagrama, puede ver cómo café
se ha codificado la palabra en codificación "UTF-8" o "Cp1252" dependiendo del tipo de terminal. En ambos ejemplos, caf
es solo ascii regular. En UTF-8, é
se codifica utilizando dos bytes. En "Cp1252", é es 0xE9 (que también es el valor del punto Unicode (no es coincidencia)). Se decode()
invoca lo correcto y la conversión a Python Unicode es exitosa:
En este diagrama, decode()
se llama con ascii
(que es lo mismo que llamar unicode()
sin una codificación dada). Como ASCII no puede contener bytes mayores que 0x7F
, esto arrojará una UnicodeDecodeError
excepción:
El sandwich de Unicode
Es una buena práctica formar un sándwich Unicode en su código, donde decodifica todos los datos entrantes en cadenas Unicode, trabaja con Unicodes y luego codifica a str
s al salir. Esto evita que se preocupe por la codificación de cadenas en el medio de su código.
Entrada / Decodificación
Código fuente
Si necesita hornear no ASCII en su código fuente, simplemente cree cadenas Unicode prefijando la cadena con un u
. P.ej
u'Zürich'
Para permitir que Python decodifique su código fuente, deberá agregar un encabezado de codificación para que coincida con la codificación real de su archivo. Por ejemplo, si su archivo fue codificado como 'UTF-8', usaría:
# encoding: utf-8
Esto solo es necesario cuando tienes no ASCII en tu código fuente .
Archivos
Por lo general, los datos no ASCII se reciben de un archivo. El io
módulo proporciona un TextWrapper que decodifica su archivo sobre la marcha, utilizando un determinado encoding
. Debe usar la codificación correcta para el archivo; no se puede adivinar fácilmente. Por ejemplo, para un archivo UTF-8:
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
my_unicode_string = my_file.read()
my_unicode_string
entonces sería adecuado para pasar a Markdown. Si es UnicodeDecodeError
de la read()
línea, entonces probablemente haya usado el valor de codificación incorrecto.
Archivos CSV
El módulo CSV Python 2.7 no admite caracteres que no sean ASCII 😩. Sin embargo, hay ayuda disponible con https://pypi.python.org/pypi/backports.csv .
Úselo como se indica arriba, pero pásele el archivo abierto:
from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
for row in csv.reader(my_file):
yield row
Bases de datos
La mayoría de los controladores de bases de datos de Python pueden devolver datos en Unicode, pero generalmente requieren una pequeña configuración. Utilice siempre cadenas Unicode para consultas SQL.
MySQL
En la cadena de conexión agregue:
charset='utf8',
use_unicode=True
P.ej
>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")
PostgreSQL
Añadir:
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
HTTP
Las páginas web se pueden codificar en casi cualquier codificación. El Content-type
encabezado debe contener un charset
campo para indicar la codificación. El contenido se puede decodificar manualmente contra este valor. Alternativamente, Python-Requests devuelve Unicodes en response.text
.
A mano
Si debe decodificar cadenas manualmente, simplemente puede hacer my_string.decode(encoding)
, donde encoding
está la codificación adecuada. Los códecs compatibles con Python 2.x se proporcionan aquí: Codificaciones estándar . De nuevo, si obtienes, UnicodeDecodeError
entonces probablemente tienes la codificación incorrecta.
La carne del sandwich
Trabaja con Unicodes como lo harías con strs normales.
Salida
stdout / impresión
print
escribe a través de la secuencia estándar. Python intenta configurar un codificador en stdout para que los Unicodes se codifiquen con la codificación de la consola. Por ejemplo, si un shell de Linux locale
es en_GB.UTF-8
, la salida se codificará en UTF-8
. En Windows, estará limitado a una página de códigos de 8 bits.
Una consola configurada incorrectamente, como una configuración regional corrupta, puede provocar errores de impresión inesperados. PYTHONIOENCODING
La variable de entorno puede forzar la codificación para stdout.
Archivos
Al igual que la entrada, io.open
se puede usar para convertir de manera transparente Unicodes en cadenas de bytes codificadas.
Base de datos
La misma configuración para la lectura permitirá que los Unicodes se escriban directamente.
Python 3
Python 3 no es más capaz de Unicode que Python 2.x, sin embargo, está un poco menos confundido sobre el tema. Por ejemplo, el regular str
ahora es una cadena Unicode y el antiguo str
ahora bytes
.
La codificación predeterminada es UTF-8, por lo que si .decode()
usa una cadena de bytes sin proporcionar una codificación, Python 3 usa la codificación UTF-8. Esto probablemente soluciona el 50% de los problemas Unicode de las personas.
Además, open()
opera en modo de texto por defecto, por lo que devuelve decodificado str
(Unicode). La codificación se deriva de su configuración regional, que tiende a ser UTF-8 en sistemas Un * x o una página de códigos de 8 bits, como windows-1251, en cuadros de Windows.
Por qué no deberías usar sys.setdefaultencoding('utf8')
Es un truco desagradable (hay una razón que debe usar reload
) que solo enmascarará problemas y dificultará su migración a Python 3.x. Comprenda el problema, solucione la causa raíz y disfrute del zen Unicode. Consulte ¿Por qué NO deberíamos usar sys.setdefaultencoding ("utf-8") en un script py? para mas detalles