Python 2 asume diferentes codificaciones de código fuente

Noté que sin la statement de encoding del código fuente, el intérprete de Python 2 asume que el código fuente está codificado en ASCII con scripts y entrada estándar :

$ python test.py # where test.py holds the line: print u'é' File "test.py", line 1 SyntaxError: Non-ASCII character '\xc3' in file test.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details $ echo "print u'é'" | python File "/dev/fd/63", line 1 SyntaxError: Non-ASCII character '\xc3' in file /dev/fd/63 on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details 

y está codificado en ISO-8859-1 con el módulo -m y los indicadores de comando -c :

 $ python -m test # where test.py holds the line: print u'é' é $ python -c "print u'é'" é 

¿Dónde está documentado?

Contraste esto con Python 3 que siempre asume que el código fuente está codificado en UTF-8 y por lo tanto imprime é en los cuatro casos.

Nota. – Probé esto en CPython 2.7.14 tanto en macOS 10.13 como en Ubuntu Linux 17.10 con la encoding de la consola configurada en UTF-8.

Los modificadores -c y -m , en última instancia (*) ejecutan el código suministrado con la instrucción exec o la función compile() , los cuales toman el código fuente de Latin-1:

La primera expresión debe evaluar una cadena Unicode, una cadena codificada Latin-1 , un objeto de archivo abierto, un objeto de código o una tupla.

Esto no está documentado, es un detalle de implementación, que puede o no ser considerado un error.

Sin embargo, no creo que valga la pena arreglarlo, y Latin-1 es un superconjunto de ASCII, por lo que se pierde muy poco. La forma en que se maneja el código de -c y -m se ha limpiado en Python 3 y es mucho más consistente allí; el código pasado con -c se decodifica utilizando la configuración regional actual, y los módulos cargados con el conmutador -m predeterminados a UTF-8, como de costumbre.


(*) Si desea conocer las implementaciones exactas utilizadas, comience en la función Py_Main() en Modules/main.c , que maneja tanto -c como -m como:

 if (command) { sts = PyRun_SimpleStringFlags(command, &cf) != 0; free(command); } else if (module) { sts = RunModule(module, 1); free(module); } 
  • -c se ejecuta a través de la función PyRun_SimpleStringFlags() , que a su vez llama a PyRun_StringFlags() . Cuando se utiliza exec un objeto de bytestring también se pasa a PyRun_StringFlags() y se supone que el código fuente contiene bytes codificados en Latin-1.
  • -m usa la función RunModule() para pasar el nombre del módulo a la función privada _run_module_as_main() en el módulo runpy , que usa pkgutil.get_loader() para cargar los metadatos del módulo, y obtiene el código del módulo con el loader.get_code() función en el cargador PEP 302 ; Si no hay disponible un código de bytes en caché, el objeto de código se produce mediante el uso de la función compile() con el modo establecido en exec .