¿Cómo imprimir texto codificado en UTF-8 en la consola en Python <3?

Estoy ejecutando un sistema Linux reciente donde todas mis configuraciones regionales son UTF-8:

LANG=de_DE.UTF-8
LANGUAGE=
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
...
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=

Ahora quiero escribir contenido codificado en UTF-8 en la consola.

En este momento, Python usa UTF-8 para la codificación FS pero se apega a ASCII para la codificación predeterminada :-(

>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> sys.getfilesystemencoding()
'UTF-8'

Pensé que la mejor manera (limpia) de hacer esto era configurar el PYTHONIOENCODING Variable ambiental. Pero parece que Python lo ignora. Al menos en mi sistema sigo recibiendo ascii como codificación predeterminada, incluso después de configurar el envvar.

# tried this in ~/.bashrc and ~/.profile (also sourced them)
# and on the commandline before running python
export PYTHONIOENCODING=UTF-8

Sin embargo, si hago lo siguiente al comienzo de un script, funciona:

>>> import sys
>>> reload(sys)  # to enable `setdefaultencoding` again
<module 'sys' (built-in)>
>>> sys.setdefaultencoding("UTF-8")
>>> sys.getdefaultencoding()
'UTF-8'

Pero ese enfoque parece sucio. Entonces, ¿cuál es una buena manera de lograr esto?

Solución

En lugar de cambiar la codificación predeterminada, que es no es Buena idea (ver la respuesta de mesilliac) - Solo envuelvo sys.stdout con un StreamWriter Me gusta esto:

sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)

Ver esta esencia para una pequeña función de utilidad, que lo maneja.

preguntado el 31 de julio de 12 a las 14:07

Quizás esto funcione: #!/usr/bin/env python # -- codificación: utf-8 -- -

Y recuerda ponerlo al principio del archivo fuente. -

Eso solo afecta la forma en que Python interpreta las cadenas literales en el código fuente. La codificación IO seguirá siendo ASCII. -

PYTHONIOENCODING no se ignora; es solo que, como su nombre lo indica, es afecta la codificación utilizada para stdin/stdout/stderr, que no es con lo que estás comprobando sys.getdefaultencoding(). -

@Brutus: ¿Cómo probaste que no funciona? Parece funcionar para mí. python -c 'import sys; print sys.stdout.encoding' da UTF-8 y PYTHONIOENCODING='C' python -c 'import sys; print sys.stdout.encoding' da C. -

5 Respuestas

Al darse cuenta de que la pregunta OP es para Linux: al terminar aquí a través de un motor de búsqueda, en Windows 10, lo siguiente soluciona el problema:

set PYTHONIOENCODING=utf8
python myscript.py

Respondido el 04 de Septiembre de 20 a las 12:09

¿Cómo imprimir texto codificado en UTF-8 en la consola en Python <3?

print u"some unicode text \N{EURO SIGN}"
print b"some utf-8 encoded bytestring \xe2\x82\xac".decode('utf-8')

es decir, si tiene una cadena Unicode, imprímala directamente. Si tiene una cadena de bytes, conviértala primero a Unicode.

Su configuración regional (LANG, LC_CTYPE) indican una configuración regional utf-8 y, por lo tanto (en teoría), podría imprimir una cadena de bytes utf-8 directamente y debería mostrarse correctamente en su terminal (si la configuración de la terminal es consistente con la configuración regional y debería serlo) pero debe evitar eso: no codifique la codificación de caracteres de su entorno dentro de su script; imprima Unicode directamente en su lugar.

Hay muchas suposiciones incorrectas en su pregunta.

No es necesario configurar PYTHONIOENCODING con su configuración local, para imprimir Unicode en el terminal. utf-8 locale admite todos los caracteres Unicode, es decir, funciona tal cual.

No necesita la solución sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout). Puede fallar si algún código (que usted no controla) necesita imprimir bytes y/o puede fallar mientras imprimiendo Unicode en la consola de Windows (página de códigos incorrecta, no se pueden imprimir caracteres no decodificables). Corrija la configuración regional y/o PYTHONIOENCODING envvar son suficientes. Además, si necesita reemplazar sys.stdout luego utilizan el io.TextIOWrapper() en lugar de codecs módulo como win-unicode-console paquete hace.

sys.getdefaultencoding() no está relacionado con su configuración local y con PYTHONIOENCODING. Su suposición de que la configuración PYTHONIOENCODING debe cambiar sys.getdefaultencoding() Es incorrecto. deberías revisar sys.stdout.encoding preferiblemente.

sys.getdefaultencoding() no se utiliza cuando imprime en la consola. Se puede usar como respaldo en Python 2 si la salida estándar se redirige a un archivo/tubería a menos que PYTHOHIOENCODING Está establecido:

$ python2 -c'import sys; print(sys.stdout.encoding)'
UTF-8
$ python2 -c'import sys; print(sys.stdout.encoding)' | cat
None
$ PYTHONIOENCODING=utf8 python2 -c'import sys; print(sys.stdout.encoding)' | cat
utf8

No llames sys.setdefaultencoding("UTF-8"); puede corromper sus datos silenciosamente y/o romper módulos de terceros que no lo esperan. Recuerda sys.getdefaultencoding() se utiliza para convertir cadenas de bytes (str) hacia/desde unicode en Python 2 implícitamente e.g., "a" + u"b". Ver también, la cita en la respuesta de @ mesilliac.

contestado el 23 de mayo de 17 a las 11:05

Si el programa no muestra los caracteres apropiados en la pantalla, es decir, un símbolo no válido, ejecute el programa con la siguiente línea de comando:

PYTHONIOENCODING=utf8 python3 yourprogram.py

O lo siguiente, si su programa es un módulo instalado globalmente:

PYTHONIOENCODING=utf8 yourprogram

En algunas plataformas como Cygwin (mintty.exe terminal) con Anaconda Python (o Python 3), simplemente ejecute export PYTHONIOENCODING=utf8 y luego ejecutar el programa no funciona, y debe hacerlo siempre cada vez PYTHONIOENCODING=utf8 yourprogram para ejecutar el programa correctamente.

En Linux, en caso de sudo, puedes intentar hacer pasar el -E argumento para exportar las variables de usuario al proceso sudo:

export PYTHONIOENCODING=utf8
sudo -E python yourprogram.py

Si intenta esto y no funcionó, deberá ingresar en un shell Sudo:

sudo /bin/bash
PYTHONIOENCODING=utf8 yourprogram

Relacionado:

  1. ¿Cómo imprimir texto codificado en UTF-8 en la consola en Python <3?
  2. ¿Cambiar la codificación predeterminada de Python?
  3. Forzar UTF-8 sobre cp1252 (Python3)
  4. Establecer permanentemente la ruta de Python para Anaconda dentro de Cygwin
  5. https://superuser.com/questions/1374339/what-does-the-e-in-sudo-e-do
  6. ¿Por qué bash -c 'var=5 printf "$var"' no imprime 5?
  7. https://unix.stackexchange.com/questions/296838/whats-the-difference-between-eval-and-exec

contestado el 07 de mayo de 19 a las 00:05

Is utf8 ¿distingue mayúsculas y minúsculas? Además, es la única configuración posible utf8 o es utf-8 tambien valido? Es solo porque he estado viendo tantas variantes... (¡y estás usando dos de ellas en tu respuesta! 😉) - Gwyneth Llewelyn

Creo que al menos para mi Python 3.7.2, el uso de UTF-8 no distingue entre mayúsculas y minúsculas y no estoy seguro de si está ignorando el guión en UTF-8. - usuario

eso tiene sentido: estaba usando Python 2.7.X y no estaba seguro de que usar... - Gwyneth Llewelyn

Parece que lograr esto no es recomendable.

Fedora sugirió utilizando la configuración regional del sistema como predeterminada, pero al parecer esto rompe otras cosas.

Aquí hay una cita del discusión de la lista de correo:

Las únicas codificaciones predeterminadas admitidas en Python son: Python 2.x: ASCII Python 3.x: UTF-8 Si cambia estas, estará solo y comenzarán a suceder cosas extrañas. La codificación predeterminada no solo afecta la traducción entre Python y el mundo exterior, sino también todas las conversiones internas entre cadenas de 8 bits y Unicode. Los trucos como lo que está sucediendo en el módulo pango (establecer la codificación predeterminada en 'utf-8' recargando el módulo del sitio para recuperar la API sys.setdefaultencoding()) son totalmente incorrectos y causarán serios problemas ya que los objetos Unicode almacenan en caché su representación codificada por defecto. No habilite el uso de una codificación predeterminada basada en la configuración regional. Si todo lo que quiere lograr es obtener las codificaciones de stdout y stdin configuradas correctamente para las tuberías, debe cambiar el atributo .encoding de esos (solo). -- Marc-André Lemburg eGenix.com

Respondido 24 Abr '17, 05:04

Así es como lo hago:

#!/usr/bin/python2.7 -S

import sys
sys.setdefaultencoding("utf-8")
import site

Nota la -S en el bangline. Eso le dice a Python que no importe automáticamente el site módulo. los site El módulo es lo que establece la codificación predeterminada y elimina el método para que no se pueda configurar nuevamente. Pero honrará lo que ya está establecido.

Respondido 31 Jul 12, 15:07

¿Podría ampliar esto en función de la respuesta que dio mesilliac? ¿Sigue siendo correcto? - Arafangión

@Arafangion El método que uso ocurre justo al comienzo de la inicialización de Python. Aún no se han creado cachés. Estoy de acuerdo en que usar el truco de recarga es malo. Esto se debe a que es posible que muchas otras cosas ya se hayan instanciado o almacenado en caché la codificación original. Por lo tanto, se me ocurrió este método que ocurre temprano. Tenga en cuenta que no hay otras importaciones antes. Esto funciona para mi. - Keith

Si bien esto me ha funcionado en las pruebas, Decidí evitarlo. Es solo que no está claro si puedo tener algún efecto secundario y huele un poco a pescado ;-) Solo envuelvo sys.stdout en un parche de StreamWriter con la codificación predeterminada (que debería ser UTF-8, al menos en los sistemas Linux modernos): sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout). - Brutus

Esta es una muy mala idea. He resuelto dos preguntas en las últimas semanas que se resolvieron eliminando sys.setdefaultencoding("utf-8") del código del usuario. En mi humilde opinión, esto solo enmascara cualquier problema subyacente: Alastair McCormack

@AlastairMcCormack Lo he usado sin ningún problema. Mientras sepas lo que está pasando, no hay problema. ¿Cuáles son los problemas subyacentes que crees que enmascara? - Keith

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.