Por qué no deberíamos usar sys.setdefaultencoding ("utf-8") en un script py?


He visto pocos scripts py que usan esto en la parte superior del script. ¿En qué casos se debe utilizar?

import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Author: smci, 2010-09-30

4 answers

Según la documentación: Esto le permite cambiar de la ASCII predeterminada 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 a unicode.

Esta función solo está disponible en el momento de inicio de Python, cuando Python escanea el entorno. Tiene que ser llamado en un módulo de todo el sistema, sitecustomize.py, Después de que este módulo ha sido evaluado, la función setdefaultencoding() se elimina del módulo sys.

La única manera de usarlo es con un truco de recarga que devuelve el atributo.

También, el uso de sys.setdefaultencoding() siempre se ha desaconsejado, y se ha convertido en un no-op en py3k. La codificación de py3k está cableada a "utf-8" y cambiarla genera un error.

Sugiero algunos consejos para lectura:

 125
Author: pyfunc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-13 21:59:12

Tl;dr{[15]]}

La respuesta es NUNCA ! (a menos que realmente sepas lo que estás haciendo)

9/10 veces la solución se puede resolver con una comprensión adecuada de la codificación/decodificación.

1/10 personas tienen una configuración regional o un entorno incorrectamente definido y necesitan establecer:

PYTHONIOENCODING="UTF-8"  

En su entorno para solucionar problemas de impresión de consola.

¿Qué hace?

sys.setdefaultencoding("utf-8") (tachado para evitar la reutilización) cambia el valor predeterminado codificación / decodificación utilizada siempre que Python 2.x necesita convertir un Unicode () a un str () (y viceversa) y la codificación no se da. I. e:

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, así que "€" = '\xe2\x82\xac', de ahí la excepción en \xe2)

O

UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)

sys.setdefaultencoding("utf-8") permitirá que estos funcionen para me, pero no necesariamente funcionará para personas que no usen UTF-8. El valor predeterminado de ASCII garantiza que las suposiciones de codificación no se integren en el código

Consola

sys.setdefaultencoding("utf-8") también tiene el efecto secundario de parecer fijar sys.stdout.encoding, utilizado 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ódigo (Windows) para establecer esto. Ocasionalmente, la configuración regional de un usuario se rompe y solo requiere PYTHONIOENCODING para 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"
€

¿Qué es tan malo con sys.setdefaultencoding ("utf-8")?

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 los métodos de manejo de excepciones se han escrito para manejar las conversiones de cadena a Unicode en cadenas que se encuentran que contienen no 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"))

Anterior a configurar defaultencoding este código sería incapaz de decodificar el " Å " en la codificación ascii y luego entraría en el controlador de excepciones para adivinar la codificación y convertirla correctamente en unicode. Impresión: Angstrom (Å®) dirige su negocio. Una vez que haya configurado el defaultencoding en utf-8, el código encontrará que el byte_string se puede interpretar como utf-8 y, por lo tanto, destrozará los datos y devolverá esto en su lugar: Angstrom (Client) ejecuta su negocio.

Cambiar lo que debería ser una constante tendrá dramáticos efectos en los módulos de los que depende. Es mejor simplemente arreglar los datos que entran y salen de su código.

Ejemplo de problema

Si bien la configuración de defaultencoding a 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 visible: UnicodeDecodeError: el códec 'utf8' no puede decodificar el byte 0x80 en la posición 3131: byte de inicio no válido

 43
Author: Alastair McCormack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-03 12:52:34
#!/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 el shell funciona, enviar a sdtout no , así que esa es una solución, escribir en stdout .

Hice otro enfoque, que no se ejecuta si sys.stdout.la codificación no se define, 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

Funcionará

 17
Author: Sérgio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-19 03:50:16
  • El primer peligro está en reload(sys).

    Cuando recargas un módulo, realmente obtienes dos copias del módulo en tu tiempo de ejecución. El módulo antiguo es un objeto Python como todo lo demás, y permanece vivo mientras haya referencias a él. Así, la mitad de los objetos estará apuntando al módulo antiguo, 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() propiamente

    Todo lo que afecta es la conversión implícitastr<->unicode. Ahora, utf-8 es la codificación más sana del planeta (compatible con ASCII y todo), la conversión ahora "solo funciona", ¿qué podría salir mal?

    Bueno, cualquier cosa. Y ese es el peligro.

    • Puede haber algún código que se base en el UnicodeError que se lanza para la entrada no ASCII, o hace la transcodificación con un error handler, que ahora produce un resultado inesperado. Y dado que todo el código se prueba con la configuración predeterminada, usted está estrictamente en territorio "no soportado" aquí, y nadie le da garantías sobre cómo se comportará su código.
    • La transcodificación puede producir resultados inesperados o inutilizables si no todo en el sistema utiliza UTF-8 porque Python 2 en realidad tiene múltiples "codificaciones de cadena predeterminadas"independientes. (Recuerde, un programa debe funcionar para el cliente, en el equipo del cliente.)
      • De nuevo, lo peor es nunca lo sabrás porque la conversión está implícita really realmente no sabes cuándo y dónde sucede. (Python Zen, koan 2 ahoy!) Nunca sabrá por qué (y si) su código funciona en un sistema y se rompe en otro. (O mejor aún, funciona en IDE y se rompe en la consola.)
 3
Author: ivan_pozdeev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-22 19:24:16