He visto algunos scripts py que usan esto en la parte superior del script. ¿En qué casos se debe usar?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
He visto algunos scripts py que usan esto en la parte superior del script. ¿En qué casos se debe usar?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Respuestas:
Según la documentación: esto le permite cambiar del ASCII predeterminado a otras codificaciones como UTF-8, que el tiempo de ejecución de Python usará siempre que tenga que decodificar un búfer de cadena para unicode.
Esta función solo está disponible en el momento de inicio de Python, cuando Python escanea el entorno. Debe llamarse en un módulo de todo el sistema sitecustomize.py
. Después de evaluar este módulo, la setdefaultencoding()
función se elimina del sys
módulo.
La única forma de usarlo es con un truco de recarga que recupera el atributo.
Además, el uso de sys.setdefaultencoding()
siempre ha sido desaconsejado , y se ha convertido en un no-op en py3k. La codificación de py3k está conectada a "utf-8" y cambiarla genera un error.
Sugiero algunos consejos para leer:
sys.stdout
cuando tiene una None
codificación, como cuando se redirige la salida de un programa Python).
sys.setdefaultencoding()
siempre se ha desaconsejado"
UTF-8
. LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'
da UTF-8
pero LC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'
da ANSI_X3.4-1968
(o tal vez otra cosa)
¡La respuesta es NUNCA ! (a menos que realmente sepas lo que estás haciendo)
9/10 veces la solución puede resolverse con una comprensión adecuada de la codificación / decodificación.
1/10 personas tienen una configuración regional o entorno incorrectamente definidos y necesitan establecer:
PYTHONIOENCODING="UTF-8"
en su entorno para solucionar problemas de impresión de la consola.
(tachado para evitar la reutilización) cambia la codificación / decodificación predeterminada utilizada cuando Python 2.x necesita convertir un Unicode () en un str () (y viceversa) y no se proporciona la codificación. Es decir:sys.setdefaultencoding("utf-8")
str(u"\u20AC")
unicode("€")
"{}".format(u"\u20AC")
En Python 2.x, la codificación predeterminada se establece en ASCII y los ejemplos anteriores fallarán con:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
(Mi consola está configurada como UTF-8, entonces "€" = '\xe2\x82\xac'
, por lo tanto, la excepción está activada \xe2
)
o
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
permitirá que estos funcionen para mí , pero no necesariamente funcionarán para las personas que no usan UTF-8. El valor predeterminado de ASCII asegura que las suposiciones de codificación no se cuecen en el códigosys.setdefaultencoding("utf-8")
También tiene el efecto secundario de aparecer en la reparación sys.setdefaultencoding("utf-8")
sys.stdout.encoding
, que se usa al imprimir caracteres en la consola. Python usa la configuración regional del usuario (Linux / OS X / Un * x) o la página de códigos (Windows) para configurar esto. Ocasionalmente, la configuración regional de un usuario está rota y solo requiere PYTHONIOENCODING
corregir la codificación de la consola .
Ejemplo:
$ export LANG=en_GB.gibberish
$ python
>>> import sys
>>> sys.stdout.encoding
'ANSI_X3.4-1968'
>>> print u"\u20AC"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
>>> exit()
$ PYTHONIOENCODING=UTF-8 python
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> print u"\u20AC"
€
La gente ha estado desarrollando contra Python 2.x durante 16 años en el entendimiento de que la codificación predeterminada es ASCII. UnicodeError
Se han escrito métodos de manejo de excepciones para manejar conversiones de cadenas a Unicode en cadenas que se encuentran que no son ASCII.
De https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/
def welcome_message(byte_string):
try:
return u"%s runs your business" % byte_string
except UnicodeError:
return u"%s runs your business" % unicode(byte_string,
encoding=detect_encoding(byte_string))
print(welcome_message(u"Angstrom (Å®)".encode("latin-1"))
Antes de establecer la codificación predeterminada, este código no podría decodificar el "Å" en la codificación ascii y luego ingresaría el controlador de excepciones para adivinar la codificación y convertirla correctamente en unicode. Impresión: Angstrom (Å®) dirige su negocio. Una vez que haya establecido la codificación predeterminada en utf-8, el código encontrará que byte_string se puede interpretar como utf-8 y, por lo tanto, destrozará los datos y devolverá esto: Angstrom (Ů) dirige su negocio.
Cambiar lo que debería ser una constante tendrá efectos dramáticos en los módulos de los que depende. Es mejor simplemente arreglar los datos que entran y salen de su código.
Si bien la configuración de la codificación predeterminada para UTF-8 no es la causa raíz en el siguiente ejemplo, muestra cómo se enmascaran los problemas y cómo, cuando cambia la codificación de entrada, el código se rompe de una manera no obvia: UnicodeDecodeError: el códec 'utf8' puede no decodifique el byte 0x80 en la posición 3131: byte de inicio no válido
sys.setdefaultencoding("utf-8")
, es bueno hacer que el código se comporte más como Python 3. Ahora es 2017. Incluso cuando escribió la respuesta en 2015, creo que ya era mejor mirar hacia adelante en lugar de hacia atrás. En realidad, fue la solución más simple para mí, cuando descubrí que mi código se comportaba de manera diferente en Python 2 dependiendo de si la salida se redirige (problema muy desagradable para Python 2). No hace falta decir que ya lo hice # coding: utf-8
, y no necesito ninguna solución para Python 3 (en realidad, tengo que enmascarar el setdefaultencoding
uso de la verificación de versión).
sys.setdefaultencoding("utf-8")
no hace que su código Py 2.x sea compatible con Python 3. Tampoco repara módulos externos que asumen que la codificación predeterminada es ASCII. Hacer que su código sea compatible con Python 3 es muy simple y no requiere este truco desagradable. Por ejemplo, por qué esto causa problemas muy reales, vea mi experiencia con Amazon jugando con esta suposición: stackoverflow.com/questions/39465220/…
PYTHONIOENCODING="UTF-8"
ayudó a mi entorno Python2.7 Django-1.11. Gracias.
detect_encoding
.
detect_encoding
es un método que podría detectar la codificación de una cadena basada en pistas del lenguaje.
#!/usr/bin/env python
#-*- coding: utf-8 -*-
u = u'moçambique'
print u.encode("utf-8")
print u
chmod +x test.py
./test.py
moçambique
moçambique
./test.py > output.txt
Traceback (most recent call last):
File "./test.py", line 5, in <module>
print u
UnicodeEncodeError: 'ascii' codec can't encode character
u'\xe7' in position 2: ordinal not in range(128)
en shell funciona, enviar a sdtout no, por lo que es una solución alternativa, escribir en stdout.
Hice otro enfoque, que no se ejecuta si sys.stdout.encoding no está definido, o en otras palabras, necesita exportar PYTHONIOENCODING = UTF-8 primero para escribir en stdout.
import sys
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)
entonces, usando el mismo ejemplo:
export PYTHONIOENCODING=UTF-8
./test.py > output.txt
trabajará
El primer peligro radica en reload(sys)
.
Cuando vuelve a cargar un módulo, en realidad obtiene dos copias del módulo en su tiempo de ejecución. El antiguo módulo es un objeto Python como todo lo demás, y permanece vivo mientras haya referencias a él. Entonces, la mitad de los objetos apuntarán al módulo anterior y la otra mitad al nuevo. Cuando realice algún cambio, nunca lo verá venir cuando algún objeto aleatorio no vea el cambio:
(This is IPython shell)
In [1]: import sys
In [2]: sys.stdout
Out[2]: <colorama.ansitowin32.StreamWrapper at 0x3a2aac8>
In [3]: reload(sys)
<module 'sys' (built-in)>
In [4]: sys.stdout
Out[4]: <open file '<stdout>', mode 'w' at 0x00000000022E20C0>
In [11]: import IPython.terminal
In [14]: IPython.terminal.interactiveshell.sys.stdout
Out[14]: <colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
Ahora sys.setdefaultencoding()
bien
Todo lo que afecta es la conversión implícitastr<->unicode
. Ahora, utf-8
es la codificación más sensata del planeta (compatible con ASCII y todo lo anterior), la conversión ahora "simplemente funciona", ¿qué podría salir mal?
Pues nada. Y ese es el peligro.
UnicodeError
lanzamiento de una entrada que no sea ASCII, o la transcodificación con un controlador de errores, que ahora produce un resultado inesperado. Y dado que todo el código se prueba con la configuración predeterminada, está estrictamente en territorio "no compatible" aquí , y nadie le ofrece garantías sobre cómo se comportará su código.