data - python open encoding
¿Cambiar la codificación predeterminada de Python? (11)
Tengo muchos problemas de "no puedo codificar" y "no puedo decodificar" con Python cuando ejecuto mis aplicaciones desde la consola. Pero en el Eclipse PyDev IDE, la codificación de caracteres predeterminada está configurada en UTF-8 , y estoy bien.
Busqué a través de la configuración de la codificación predeterminada, y la gente dice que Python elimina la función sys.setdefaultencoding
en el inicio, y no podemos usarla.
Entonces, ¿cuál es la mejor solución para eso?
¿Quieres escribir palabras en español (para escribir la ñ en python)
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
print "Piña"
Aquí hay un método más simple (hack) que le devuelve la función setdefaultencoding()
que se eliminó de sys
:
import sys
# sys.setdefaultencoding() does not exist, here!
reload(sys) # Reload does the trick!
sys.setdefaultencoding(''UTF8'')
Sin embargo, esto no es algo seguro de hacer : esto es obviamente un truco, ya que sys.setdefaultencoding()
se elimina intencionalmente de sys
cuando se inicia Python. Al volver a activarlo y cambiar la codificación predeterminada, se puede descifrar el código que depende de que ASCII sea el predeterminado (este código puede ser de terceros, lo que generalmente haría que arreglarlo sea imposible o peligroso).
Comenzando con PyDev 3.4.1, la codificación predeterminada ya no se cambia. Vea este boleto para más detalles.
Para las versiones anteriores, una solución es asegurarse de que PyDev no se ejecute con UTF-8 como la codificación predeterminada. En Eclipse, ejecute la configuración del diálogo ("ejecutar configuraciones", si no recuerdo mal); puede elegir la codificación predeterminada en la pestaña común. Cámbielo a US-ASCII si quiere tener estos errores ''temprano'' (en otras palabras: en su entorno PyDev). También vea una publicación de blog original para esta solución .
Con respecto a python2 (y solo python2), algunas de las respuestas anteriores se basan en el uso del siguiente hack:
import sys
reload(sys) # Reload is a hack
sys.setdefaultencoding(''UTF8'')
Se desaconseja su uso (ver esto o this )
En mi caso, viene con un efecto secundario: estoy usando notebooks ipython, y una vez que ejecuto el código, la función''print ''ya no funciona. Supongo que habría una solución para eso, pero aún así creo que usar el hack no debería ser la opción correcta.
Después de probar muchas opciones, la que funcionaba para mí utilizaba el mismo código en sitecustomize.py
, donde está destinado a ser ese fragmento de código . Después de evaluar ese módulo, la función setdefaultencoding se elimina de sys.
Entonces, la solución es agregar al archivo /usr/lib/python2.7/sitecustomize.py
el código:
import sys
sys.setdefaultencoding(''UTF8'')
Cuando uso virtualenvwrapper el archivo que edito es ~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py
.
Y cuando uso con cuadernos y conda de python, es ~/anaconda2/lib/python2.7/sitecustomize.py
Este es el enfoque que utilicé para producir código que era compatible tanto con python2 como con python3 y siempre producía salida utf8 . Encontré esta respuesta en otro lugar, pero no recuerdo la fuente.
Este enfoque funciona reemplazando sys.stdout
por algo que no es del todo parecido a un archivo (pero que solo utiliza elementos en la biblioteca estándar). Esto bien puede causar problemas para las bibliotecas subyacentes, pero en el caso simple en que tenga un buen control sobre cómo se usa sys.stdoutout a través de su marco, esto puede ser un enfoque razonable.
sys.stdout = io.open(sys.stdout.fileno(), ''w'', encoding=''utf8'')
Este es un truco rápido para cualquiera que esté (1) En una plataforma Windows (2) ejecutando Python 2.7 y (3) molesto porque es una buena pieza de software (es decir, no escrita por usted, no es candidata inmediata para codificar / decodificar maniobras) no mostrará los "bonitos caracteres unicode" en el entorno IDLE (Pythonwin imprime unicode fino), por ejemplo, los limpios símbolos de First Order Logic que Stephan Boyer usa en la salida de su probador pedagógico en First Order Logic Prover .
No me gustó la idea de forzar la recarga de un sistema y no pude lograr que el sistema cooperara con la configuración de variables de entorno como PYTHONIOENCODING (intenté la variable de entorno directa de Windows y también dejé eso en un sitecustomize.py en site-packages como uno liner = ''utf-8'').
Entonces, si estás dispuesto a hackear tu camino hacia el éxito, ve a tu directorio IDLE, típicamente: "C: / Python27 / Lib / idlelib" Localiza el archivo IOBinding.py. Haga una copia de ese archivo y guárdelo en otro lugar para que pueda volver al comportamiento original cuando lo desee. Abra el archivo en el idlelib con un editor (por ejemplo, IDLE). Ir a esta área de código:
# Encoding for file names
filesystemencoding = sys.getfilesystemencoding()
encoding = "ascii"
if sys.platform == ''win32'':
# On Windows, we could use "mbcs". However, to give the user
# a portable encoding name, we need to find the code page
try:
# --> 6/5/17 hack to force IDLE to display utf-8 rather than cp1252
# --> encoding = locale.getdefaultlocale()[1]
encoding = ''utf-8''
codecs.lookup(encoding)
except LookupError:
pass
En otras palabras, comente la línea de código original después de la '' prueba '' que estaba haciendo que la variable de codificación sea igual a locale.getdefaultlocale (porque eso le dará cp1252 que no desea) y en su lugar fuerza bruta a ''utf-8 ''(agregando la línea'' encoding = ''utf-8 '' como se muestra).
Creo que esto solo afecta a la pantalla IDLE para stdout y no a la codificación utilizada para nombres de archivos, etc. (que se obtiene en el sistema de archivos anterior). Si tiene un problema con cualquier otro código que ejecute en IDLE más tarde, simplemente reemplace el archivo IOBinding.py con el archivo original no modificado.
Esto solucionó el problema para mí.
import os
os.environ["PYTHONIOENCODING"] = "utf-8"
Hay una entrada perspicaz en el blog al respecto.
Consulte https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/ .
Parafraseo su contenido a continuación.
En python 2, que no estaba tan fuertemente tipado con respecto a la codificación de cadenas, podría realizar operaciones en cadenas codificadas de forma diferente y tener éxito. Por ejemplo, lo siguiente sería True
.
u''Toshio'' == ''Toshio''
Eso se mantendría para cada cadena (normal, no prefijada) codificada en sys.getdefaultencoding()
, que de manera predeterminada era ascii
, pero no otras.
La codificación predeterminada estaba destinada a cambiarse en todo el sistema en site.py
, pero no en otro lugar. Los hacks (también presentados aquí) para configurarlo en módulos de usuario fueron solo eso: hacks, no la solución.
Python 3 modificó la codificación del sistema para usar utf-8 (cuando LC_CTYPE es consciente de unicodo), pero el problema fundamental se resolvió con el requisito de codificar explícitamente cadenas de "byte" siempre que se utilicen con cadenas de caracteres unicode.
Primero: reload(sys)
y establecer algunas codificaciones predeterminadas al azar con respecto a la necesidad de una transmisión de terminal de salida es una mala práctica. reload
menudo cambia cosas en sys que se han puesto en su lugar dependiendo del entorno, por ejemplo, sys.stdin / stdout streams, sys.excepthook, etc.
Resolviendo el problema de codificación en stdout
La mejor solución que conozco para resolver el problema de codificación de print
cadenas de Unicode y más allá de Ascii str
''s (por ejemplo, de literales) en sys.stdout es: cuidar un sys.stdout (objeto similar a un archivo) que es capaz y opcionalmente tolerante con respecto a las necesidades:
Cuando
sys.stdout.encoding
esNone
por alguna razón, o inexistente, o erróneamente falso o "menos" de lo que la terminal stdout o stream realmente es capaz de hacer, entonces intente proporcionar un atributo.encoding
correcto. Por último, reemplazandosys.stdout & sys.stderr
por un objeto similar a un archivo de traducción.Cuando la terminal / stream todavía no puede codificar todos los caracteres de caracteres Unicode, y cuando no quiere romper las
print
simplemente por eso, puede introducir un comportamiento de codificación con reemplazo en el objeto de traducción de archivo.
Aquí un ejemplo:
#!/usr/bin/env python
# encoding: utf-8
import sys
class SmartStdout:
def __init__(self, encoding=None, org_stdout=None):
if org_stdout is None:
org_stdout = getattr(sys.stdout, ''org_stdout'', sys.stdout)
self.org_stdout = org_stdout
self.encoding = encoding or /
getattr(org_stdout, ''encoding'', None) or ''utf-8''
def write(self, s):
self.org_stdout.write(s.encode(self.encoding, ''backslashreplace''))
def __getattr__(self, name):
return getattr(self.org_stdout, name)
if __name__ == ''__main__'':
if sys.stdout.isatty():
sys.stdout = sys.stderr = SmartStdout()
us = u''aouäöüфżß²''
print us
sys.stdout.flush()
Uso de literales de cadenas simples beyond-ascii en el código Python 2/2 + 3
La única buena razón para cambiar la codificación global predeterminada (solo para UTF-8) creo que se trata de una decisión de código fuente de aplicación, y no debido a problemas de codificación de flujo de E / S: Para escribir literales más allá de ASCII en código sin ser forzado para usar siempre el u''string''
estilo unicode de u''string''
. Esto puede hacerse de manera bastante consistente (a pesar de lo que dice el artículo de Anonbadger ) al tomar una base de código fuente de Python 2 o Python 2 + 3 que usa literalmente cadenas literales ascii o UTF-8 consistentemente - en la medida en que esas cadenas puedan silenciarse conversión unicode y moverse entre módulos o potencialmente ir a stdout. Para eso, prefiera " # encoding: utf-8
" o ascii (sin declaración). Cambie o elimine las bibliotecas que todavía se basan de una manera muy tonta y fatal en los errores de codificación por defecto de asci más allá de la clave n. ° 127 (que hoy es raro).
Y haga esto al inicio de la aplicación (y / o a través de sitecustomize.py) además del esquema SmartStdout
anterior, sin utilizar reload(sys)
:
...
def set_defaultencoding_globally(encoding=''utf-8''):
assert sys.getdefaultencoding() in (''ascii'', ''mbcs'', encoding)
import imp
_sys_org = imp.load_dynamic(''_sys_org'', ''sys'')
_sys_org.setdefaultencoding(encoding)
if __name__ == ''__main__'':
sys.stdout = sys.stderr = SmartStdout()
set_defaultencoding_globally(''utf-8'')
s = ''aouäöüфżß²''
print s
De esta forma, los literales de cadena y la mayoría de las operaciones (excepto la iteración de caracteres) funcionan cómodamente sin pensar en la conversión de Unicode como si solo hubiera Python3. Por supuesto, las E / S de archivos siempre requieren cuidados especiales con respecto a las codificaciones, como ocurre en Python3.
Nota: las cadenas SmartStdout
se convierten implícitamente de utf-8 a unicode en SmartStdout
antes de convertirse en el flujo de salida que se codifica.
Si obtiene este error cuando intenta canalizar / redireccionar el resultado de su script
UnicodeEncodeError: ''ascii'' codec can''t encode characters in position 0-5: ordinal not in range(128)
Solo exporta PYTHONIOENCODING en la consola y luego ejecuta tu código.
export PYTHONIOENCODING=utf8
A) Para controlar el resultado de sys.getdefaultencoding()
:
python -c ''import sys; print(sys.getdefaultencoding())''
ascii
Entonces
echo "import sys; sys.setdefaultencoding(''utf-16-be'')" > sitecustomize.py
y
PYTHONPATH=".:$PYTHONPATH" python -c ''import sys; print(sys.getdefaultencoding())''
utf-16-be
Podrías poner tu sitecustomize.py más alto en tu PYTHONPATH
.
También puede intentar reload(sys).setdefaultencoding
a reload(sys).setdefaultencoding
por @EOL
B) Para controlar stdin.encoding
y stdout.encoding
, desea establecer PYTHONIOENCODING
:
python -c ''import sys; print(sys.stdin.encoding, sys.stdout.encoding)''
ascii ascii
Entonces
PYTHONIOENCODING="utf-16-be" python -c ''import sys;
print(sys.stdin.encoding, sys.stdout.encoding)''
utf-16-be utf-16-be
Finalmente: ¡puedes usar A) o B) o ambos!