Desde el shell Python 2.6:
>>> import sys
>>> print sys.getdefaultencoding()
ascii
>>> print u'\xe9'
é
>>>
Esperaba tener algo de galimatías o un error después de la declaración de impresión, ya que el carácter "é" no es parte de ASCII y no he especificado una codificación. Supongo que no entiendo qué significa ASCII ser la codificación predeterminada.
EDITAR
Moví la edición a la sección Respuestas y la acepté como se sugiere.
'\xe9'
en un terminal configurado para UTF-8 no se imprimiráé
. Imprimirá un carácter de reemplazo (generalmente un signo de interrogación) ya\xe9
que no es una secuencia UTF-8 válida (le faltan dos bytes que deberían haber seguido ese byte inicial). Sin duda, no se interpretará como Latin-1 en su lugar.\xe9
a imprimiré
.Respuestas:
Gracias a fragmentos de varias respuestas, creo que podemos unir una explicación.
Al intentar imprimir una cadena Unicode, u '\ xe9', Python intenta implícitamente codificar esa cadena usando el esquema de codificación actualmente almacenado en sys.stdout.encoding. Python en realidad recoge esta configuración del entorno desde el que se inició. Si no puede encontrar una codificación adecuada del entorno, solo entonces vuelve a su valor predeterminado , ASCII.
Por ejemplo, yo uso un shell bash cuya codificación por defecto es UTF-8. Si inicio Python desde allí, recoge y usa esa configuración:
Salgamos por un momento del shell de Python y configuremos el entorno de bash con alguna codificación falsa:
Luego, vuelva a iniciar el shell de Python y verifique que efectivamente vuelva a su codificación ASCII predeterminada.
¡Bingo!
Si ahora intenta generar algún carácter unicode fuera de ASCII, debería recibir un buen mensaje de error
Salgamos de Python y descartemos el bash shell.
Ahora observaremos lo que sucede después de que Python genera cadenas. Para esto, primero comenzaremos un shell bash dentro de un terminal gráfico (uso el terminal Gnome) y configuraremos el terminal para decodificar la salida con ISO-8859-1 aka latin-1 (los terminales gráficos generalmente tienen una opción para establecer el carácter Codificación en uno de sus menús desplegables). Tenga en cuenta que esto no cambia la codificación del entorno de shell real , solo cambia la forma en que el terminal descodificará la salida que se le da, un poco como lo hace un navegador web. Por lo tanto, puede cambiar la codificación del terminal, independientemente del entorno del shell. Entonces, comencemos Python desde el shell y verifiquemos que sys.stdout.encoding esté configurado para la codificación del entorno del shell (UTF-8 para mí):
(1) python genera una cadena binaria tal cual, la terminal la recibe e intenta hacer coincidir su valor con el mapa de caracteres latin-1. En latin-1, 0xe9 o 233 produce el carácter "é" y eso es lo que muestra el terminal.
(2) python intenta codificar implícitamente la cadena Unicode con cualquier esquema actualmente configurado en sys.stdout.encoding, en este caso es "UTF-8". Después de la codificación UTF-8, la cadena binaria resultante es '\ xc3 \ xa9' (ver explicación posterior). El terminal recibe el flujo como tal e intenta decodificar 0xc3a9 usando latin-1, pero latin-1 va de 0 a 255 y, por lo tanto, solo decodifica flujos de 1 byte a la vez. 0xc3a9 tiene 2 bytes de longitud, por lo tanto, el decodificador latin-1 lo interpreta como 0xc3 (195) y 0xa9 (169) y eso produce 2 caracteres: Ã y ©.
(3) python codifica el punto de código unicode u '\ xe9' (233) con el esquema latin-1. Resulta que el rango de puntos del código latin-1 es 0-255 y apunta exactamente al mismo carácter que Unicode dentro de ese rango. Por lo tanto, los puntos de código Unicode en ese rango producirán el mismo valor cuando se codifican en latin-1. Entonces u '\ xe9' (233) codificado en latin-1 también producirá la cadena binaria '\ xe9'. Terminal recibe ese valor e intenta hacer coincidirlo en el mapa de caracteres latin-1. Al igual que el caso (1), produce "é" y eso es lo que se muestra.
Cambiemos ahora la configuración de codificación del terminal a UTF-8 desde el menú desplegable (como cambiaría la configuración de codificación de su navegador web). No es necesario detener Python o reiniciar el shell. La codificación del terminal ahora coincide con la de Python. Intentemos imprimir de nuevo:
(4) python genera una cadena binaria tal cual. El terminal intenta decodificar ese flujo con UTF-8. Pero UTF-8 no entiende el valor 0xe9 (ver explicación posterior) y, por lo tanto, no puede convertirlo en un punto de código Unicode. No se encontró ningún punto de código, no se imprimió ningún carácter.
(5) python intenta codificar implícitamente la cadena Unicode con lo que esté en sys.stdout.encoding. Todavía "UTF-8". La cadena binaria resultante es '\ xc3 \ xa9'. El terminal recibe el flujo e intenta decodificar 0xc3a9 también usando UTF-8. Devuelve el valor del código 0xe9 (233), que en el mapa de caracteres Unicode apunta al símbolo "é". El terminal muestra "é".
(6) python codifica una cadena unicode con latin-1, produce una cadena binaria con el mismo valor '\ xe9'. Nuevamente, para el terminal esto es más o menos lo mismo que el caso (4).
Conclusiones: - Python genera cadenas no unicode como datos sin procesar, sin considerar su codificación predeterminada. El terminal simplemente los muestra si su codificación actual coincide con los datos. - Python genera cadenas Unicode después de codificarlas utilizando el esquema especificado en sys.stdout.encoding. - Python obtiene esa configuración del entorno del shell. - el terminal muestra la salida de acuerdo con su propia configuración de codificación. - la codificación del terminal es independiente de la del shell.
Más detalles sobre unicode, UTF-8 y latin-1:
Unicode es básicamente una tabla de caracteres donde algunas teclas (puntos de código) se han asignado convencionalmente para señalar algunos símbolos. por ejemplo, por convención, se ha decidido que la clave 0xe9 (233) es el valor que apunta al símbolo 'é'. ASCII y Unicode usan los mismos puntos de código de 0 a 127, al igual que latin-1 y Unicode de 0 a 255. Es decir, 0x41 puntos a 'A' en ASCII, latin-1 y Unicode, 0xc8 puntos a 'Ü' en latin-1 y Unicode, 0xe9 apunta a 'é' en latin-1 y Unicode.
Cuando se trabaja con dispositivos electrónicos, los puntos de código Unicode necesitan una forma eficiente de representarse electrónicamente. De eso se tratan los esquemas de codificación. Existen varios esquemas de codificación Unicode (utf7, UTF-8, UTF-16, UTF-32). El enfoque de codificación más intuitivo y directo sería simplemente usar el valor de un punto de código en el mapa Unicode como su valor para su forma electrónica, pero Unicode actualmente tiene más de un millón de puntos de código, lo que significa que algunos de ellos requieren 3 bytes para ser expresado Para trabajar de manera eficiente con el texto, una asignación 1 a 1 sería poco práctica, ya que requeriría que todos los puntos de código se almacenen exactamente en la misma cantidad de espacio, con un mínimo de 3 bytes por carácter, independientemente de su necesidad real.
La mayoría de los esquemas de codificación tienen deficiencias con respecto al requisito de espacio, los más económicos no cubren todos los puntos de código Unicode, por ejemplo, ascii solo cubre los primeros 128, mientras que latin-1 cubre los primeros 256. Otros que intentan ser más completos también terminan siendo un desperdicio, ya que requieren más bytes de los necesarios, incluso para los caracteres "baratos" comunes. UTF-16, por ejemplo, utiliza un mínimo de 2 bytes por carácter, incluidos aquellos en el rango ASCII ('B', que es 65, todavía requiere 2 bytes de almacenamiento en UTF-16). UTF-32 es aún más derrochador ya que almacena todos los caracteres en 4 bytes.
UTF-8 resulta haber resuelto inteligentemente el dilema, con un esquema capaz de almacenar puntos de código con una cantidad variable de espacios de bytes. Como parte de su estrategia de codificación, UTF-8 ata puntos de código con bits de bandera que indican (presumiblemente a los decodificadores) sus requisitos de espacio y sus límites.
Codificación UTF-8 de puntos de código Unicode en el rango ASCII (0-127):
Por ejemplo, el punto de código Unicode para 'B' es '0x42' o 0100 0010 en binario (como dijimos, es lo mismo en ASCII). Después de codificar en UTF-8 se convierte en:
Codificación UTF-8 de puntos de código Unicode por encima de 127 (no ASCII):
por ejemplo, el punto de código 'é' Unicode es 0xe9 (233).
Cuando UTF-8 codifica este valor, determina que el valor es mayor que 127 y menor que 2048, por lo tanto, debe codificarse en 2 bytes:
Los puntos de código 0xe9 Unicode después de la codificación UTF-8 se convierten en 0xc3a9. Que es exactamente como lo recibe el terminal. Si su terminal está configurado para decodificar cadenas usando latin-1 (una de las codificaciones heredadas no unicode), verá à ©, porque sucede que 0xc3 en latin-1 apunta a à y 0xa9 a ©.
fuente
Cuando los caracteres Unicode se imprimen en stdout,
sys.stdout.encoding
se utiliza. Se supone que hay un carácter que no es Unicodesys.stdout.encoding
y se envía al terminal. En mi sistema (Python 2):sys.getdefaultencoding()
solo se usa cuando Python no tiene otra opción.Tenga en cuenta que Python 3.6 o posterior ignora las codificaciones en Windows y utiliza las API de Unicode para escribir Unicode en el terminal. No hay advertencias UnicodeEncodeError y se muestra el carácter correcto si la fuente lo admite. Incluso si la fuente no es compatible, los caracteres se pueden cortar y pegar desde el terminal a una aplicación con una fuente compatible y será correcto. ¡Potenciar!
fuente
Python REPL intenta elegir qué codificación usar de su entorno. Si encuentra algo cuerdo, entonces todo funciona. Cuando no puede darse cuenta de lo que está sucediendo, se da cuenta.
fuente
TypeError: readonly attribute
en 2.7.2Usted ha especificado una codificación mediante la introducción de una cadena Unicode explícita. Compare los resultados de no usar el
u
prefijo.En el caso de
\xe9
entonces Python asume su codificación predeterminada (Ascii), imprimiendo ... algo en blanco.fuente
Esto funciona para mi:
fuente
Según las codificaciones y conversiones de cadenas implícitas / implícitas de Python :
print
ingunicode
, esencode
d con<file>.encoding
.encoding
no se establece,unicode
se convierte implícitamente enstr
(ya que el códec para eso essys.getdefaultencoding()
, es decirascii
, cualquier carácter nacional causaría aUnicodeEncodeError
)encoding
se infiere del entorno. Por lo general, se configura paratty
transmisiones (desde la configuración regional del terminal), pero es probable que no se configure para tuberíasprint u'\xe9'
es probable que a tenga éxito cuando la salida es a una terminal, y falla si se redirige. Una solución esencode()
la cadena con la codificación deseada antes deprint
ing.print
ingstr
, los bytes se envían a la secuencia tal cual. Los glifos que muestre el terminal dependerán de su configuración regional.fuente