sys.argv como bytes en Python 3k

Como Python 3k introduce una distinción estricta entre cadenas y bytes, los argumentos de la línea de comandos en la matriz sys.argv se presentan como cadenas. A veces es necesario tratar los argumentos como bytes, por ejemplo, cuando se pasa una ruta que no necesita estar en ninguna encoding de caracteres en particular en Unix.

Veamos un ejemplo. Un breve progtwig de Python 3k argv.py sigue:

 import sys print(sys.argv[1]) print(b'bytes') 

Cuando se ejecuta como python3.1 argv.py français , produce el resultado esperado:

français

bbytes

Tenga en cuenta que el argumento français está en mi encoding de configuración regional. Sin embargo, cuando pasamos el argumento en una encoding diferente obtenemos un error: python3.1 argv.py `echo français|iconv -t latin1`

 Traceback (most recent call last): File "argv.py", line 3, in  print(sys.argv[1]) UnicodeEncodeError: 'utf-8' codec can't encode character '\udce7' in position 4: surrogates not allowed 

¿Cómo debemos pasar datos binarios al progtwig Python 3k a través de argumentos de línea de comando? Un ejemplo de uso es pasar una ruta a un archivo de un usuario que usa otra configuración regional.

Tenga en cuenta que el error es un UnicodeEncodeError lugar de UnicodeDecodeError . Python conserva los bytes exactos que se pasan en la línea de comandos (a través del controlador de errores de surrogateescape archivo PEP 383), pero esos bytes no son válidos de UTF-8 y, por lo tanto, no pueden codificarse como tales para escribir en la consola.

La mejor manera de lidiar con esto es usar el conocimiento del nivel de aplicación de la encoding correcta para reinterpretar el argumento de la línea de comandos dentro de la aplicación, como se muestra en el siguiente código de ejemplo:

 $ python3.2 -c "import os, sys; print(os.fsencode(sys.argv[1]).decode('latin-1'))" `echo français|iconv -t latin1` français 

La os.fsencode función os.fsencode invierte la transformación que Python aplicó automáticamente al procesar los argumentos de la línea de comando. La invocación del método de decode('latin-1') realiza la conversión correcta para obtener una cadena decodificada correctamente.

Python 3.2 agregó os.fsencode específicamente para hacer que este tipo de problema sea más fácil de manejar.

Para Python 3.1 , la construcción equivalente para os.fsencode(sys.argv[1]) es sys.argv[1].encode(sys.getfilesystemencoding(), 'surrogateescape')

Editado en febrero de 2013: actualizado para Python 3.2+, y para evitar asumir que Python autodetegió “UTF-8” como la encoding de la línea de comandos

Tu puedes hacer:

sys.argv[1].encode() o, si conoce la encoding, bytes(sys.argv[1], 'latin-1') como argumento o como bytes(sys.argv[1], 'latin-1') llamada bytes(sys.argv[1], 'latin-1') .

Ambos deben proporcionarle una representación de bytes de la cadena Unicode.

Por defecto, Python3 utiliza UTF-8.