python encoding terminal stdout python-2.x

Configuración de la codificación correcta al canalizar la salida estándar en Python



encoding terminal (10)

En Ubuntu 12.10 y GNOME Terminal, no se produce ningún error cuando el programa se está imprimiendo en stdout o conectado a una tubería para otros programas. Tanto la codificación de archivo como la codificación de terminal es UTF-8 .

$ cat a.py # -*- coding: utf-8 -*- print "åäö" $ python a.py åäö $ python a.py | tee out åäö

¿Qué sistema operativo y emulador de terminal estás usando? Escuché que algunos de mis colegas tienen problemas similares al usar iTerm 2 y OS X; iTerm 2 puede ser el culpable.

Actualización: esta respuesta es incorrecta - ver comentarios para detalles

Al canalizar la salida de un programa Python, el intérprete de Python se confunde con respecto a la codificación y la establece en Ninguno. Esto significa un programa como este:

# -*- coding: utf-8 -*- print u"åäö"

funcionará bien cuando se ejecuta normalmente, pero falla con:

UnicodeEncodeError: el codec ''ascii'' no puede codificar el carácter u ''/ xa0'' en la posición 0: ordinal no está dentro del rango (128)

cuando se utiliza en una secuencia de tubería.

¿Cuál es la mejor manera de hacer que esto funcione cuando se canaliza? ¿Puedo simplemente decirle que use cualquier codificación del shell / sistema de archivos / lo que esté usando?

Las sugerencias que he visto hasta ahora son modificar su site.py directamente, o codificar la codificación predeterminada usando este truco:

# -*- coding: utf-8 -*- import sys reload(sys) sys.setdefaultencoding(''utf-8'') print u"åäö"

¿Hay una mejor manera de hacer que la tubería funcione?


Me encontré con este problema en una aplicación heredada y fue difícil identificar dónde se imprimió. Me ayudé con este truco:

# encoding_utf8.py import codecs import builtins def print_utf8(text, **kwargs): print(str(text).encode(''utf-8''), **kwargs) def print_utf8(fn): def print_fn(*args, **kwargs): return fn(str(*args).encode(''utf-8''), **kwargs) return print_fn builtins.print = print_utf8(print)

En la parte superior de mi script, test.py:

import encoding_utf8 string = ''Axwell Λ Ingrosso'' print(string)

Tenga en cuenta que esto cambia TODAS las llamadas a imprimir para usar una codificación, por lo que su consola imprimirá esto:

$ python test.py b''Axwell /xce/x9b Ingrosso''


Pensé que mencionaría algo aquí con lo que tuve que pasar mucho tiempo experimentando antes de que finalmente me diera cuenta de lo que estaba pasando. Esto puede ser tan obvio para todos aquí que no se han molestado en mencionarlo. ¡Pero me hubiera ayudado si lo hubieran hecho, entonces sobre ese principio ...!

NB: Estoy usando Jython específicamente, v 2.7, así que posiblemente esto no se aplique a CPython ...

NB2: las dos primeras líneas de mi archivo .py aquí son:

# -*- coding: utf-8 -*- from __future__ import print_function

El mecanismo de construcción de cadena "%" (AKA "operador de interpolación") también causa problemas ADICIONALES ... Si la codificación predeterminada del "entorno" es ASCII e intenta hacer algo como

print( "bonjour, %s" % "fréd" ) # Call this "print A"

No tendrá dificultades para ejecutar Eclipse ... En una CLI de Windows (ventana de DOS) encontrará que la codificación es la página de códigos 850 (mi sistema operativo Windows 7) o algo similar, que puede manejar al menos caracteres con acento europeo, por lo que trabajaré

print( u"bonjour, %s" % "fréd" ) # Call this "print B"

También funcionará.

Si, OTOH, dirige a un archivo desde la CLI, la codificación de la salida estándar será Ninguna, que de forma predeterminada será ASCII (en mi sistema operativo), que no podrá manejar ninguna de las impresiones anteriores ... (codificación temida error).

Entonces, podría pensar en redireccionar su salida estándar usando

sys.stdout = codecs.getwriter(''utf8'')(sys.stdout)

e intente ejecutar en la tubería CLI a un archivo ... Muy extrañamente, la impresión A de arriba funcionará ... ¡Pero la impresión B de arriba arrojará el error de codificación! Sin embargo, lo siguiente funcionará bien:

print( u"bonjour, " + "fréd" ) # Call this "print C"

La conclusión a la que he llegado (provisionalmente) es que si una cadena que se especifica como una cadena Unicode usa el prefijo "u" se envía al mecanismo% -handling, parece implicar el uso de la codificación del entorno por defecto, independientemente de Si ha configurado la salida estándar para redireccionar!

La forma en que la gente trata esto es una cuestión de elección. Daría la bienvenida a un experto de Unicode para decir por qué sucede esto, si me he equivocado de alguna manera, cuál es la solución preferida a esto, si también se aplica a CPython , si sucede en Python 3, etc., etc.


Podría "automatizarlo" con una llamada a:

def __fix_io_encoding(last_resort_default=''UTF-8''): import sys if [x for x in (sys.stdin,sys.stdout,sys.stderr) if x.encoding is None] : import os defEnc = None if defEnc is None : try: import locale defEnc = locale.getpreferredencoding() except: pass if defEnc is None : try: defEnc = sys.getfilesystemencoding() except: pass if defEnc is None : try: defEnc = sys.stdin.encoding except: pass if defEnc is None : defEnc = last_resort_default os.environ[''PYTHONIOENCODING''] = os.environ.get("PYTHONIOENCODING",defEnc) os.execvpe(sys.argv[0],sys.argv,os.environ) __fix_io_encoding() ; del __fix_io_encoding

Sí, es posible obtener un bucle infinito aquí si este "setenv" falla.


Primero, con respecto a esta solución:

# -*- coding: utf-8 -*- print u"åäö".encode(''utf-8'')

No es práctico imprimir explícitamente con una codificación determinada cada vez. Eso sería repetitivo y propenso a errores.

Una mejor solución es cambiar sys.stdout al inicio de su programa, para codificar con una codificación seleccionada. Aquí hay una solución que encontré en Python: ¿Cómo se elige sys.stdout.encoding? , en particular un comentario de "toka":

import sys import codecs sys.stdout = codecs.getwriter(''utf8'')(sys.stdout)


Puede intentar cambiar la variable de entorno "PYTHONIOENCODING" por "utf_8". He escrito una página en mi prueba con este problema .

Tl; dr de la entrada del blog:

import sys, locale, os print(sys.stdout.encoding) print(sys.stdout.isatty()) print(locale.getpreferredencoding()) print(sys.getfilesystemencoding()) print(os.environ["PYTHONIOENCODING"]) print(chr(246), chr(9786), chr(9787))

te dio

utf_8 False ANSI_X3.4-1968 ascii utf_8 ö ☺ ☻


Su código funciona cuando se ejecuta en una secuencia de comandos porque Python codifica la salida a cualquier codificación que esté utilizando su aplicación de terminal. Si estás canalizando debes codificarlo tú mismo.

Una regla de oro es: Siempre use Unicode internamente. Decodifica lo que recibes y codifica lo que envías.

# -*- coding: utf-8 -*- print u"åäö".encode(''utf-8'')

Otro ejemplo didáctico es un programa Python para convertir entre ISO-8859-1 y UTF-8, haciendo que todo entre mayúsculas y minúsculas.

import sys for line in sys.stdin: # Decode what you receive: line = line.decode(''iso8859-1'') # Work with Unicode internally: line = line.upper() # Encode what you send: line = line.encode(''utf-8'') sys.stdout.write(line)

Establecer la codificación predeterminada del sistema es una mala idea, ya que algunos módulos y bibliotecas que utiliza pueden confiar en el hecho de que es ASCII. No lo hagas


Tuve un problema similar la semana pasada . Fue fácil de arreglar en mi IDE (PyCharm).

Aquí estaba mi solución:

Comenzando desde la barra de menú de PyCharm: Archivo -> Configuración ... -> Editor -> Codificaciones de archivos, luego configure: "Codificación IDE", "Codificación del proyecto" y "Codificación predeterminada para archivos de propiedades" TODO a UTF-8 y ahora funciona como un encanto.

¡Espero que esto ayude!


Una versión desechable discutible de la respuesta de Craig McQueen.

import sys, codecs class EncodedOut: def __init__(self, enc): self.enc = enc self.stdout = sys.stdout def __enter__(self): if sys.stdout.encoding is None: w = codecs.getwriter(self.enc) sys.stdout = w(sys.stdout) def __exit__(self, exc_ty, exc_val, tb): sys.stdout = self.stdout

Uso:

with EncodedOut(''utf-8''): print u''ÅÄÖåäö''


export PYTHONIOENCODING=utf-8

hacer el trabajo, pero no puede configurarlo en Python en sí ...

lo que podemos hacer es verificar si no está configurado y decirle al usuario que lo configure antes de llamar al script con:

if __name__ == ''__main__'': if (sys.stdout.encoding is None): print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout." exit(1)

Actualizar para responder al comentario: el problema simplemente existe cuando se canaliza a la salida estándar. He probado en Fedora 25 Python 2.7.13

python --version Python 2.7.13

gato b.py

#!/usr/bin/env python #-*- coding: utf-8 -*- import sys print sys.stdout.encoding

ejecutando ./b.py

UTF-8

corriendo ./b.py | Menos

None