2011-08-08 11 views
8

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

Veamos un ejemplo. Un breve programa en Python 3k argv.py siguiente:

salida
import sys 

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

Cuando se ejecuta como python3.1 argv.py français Produce espera:

français

b'bytes'

Tenga en cuenta que el argumento français está en mi local de codificación. Sin embargo, cuando se pasa el argumento de una codificación 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 <module> 
    print(sys.argv[1]) 
    UnicodeEncodeError: 'utf-8' codec can't encode character '\udce7' in position 4: surrogates not allowed 

¿cómo vamos a pasar datos binarios a través de programa de Python 3k argumentos de línea de comandos? Un ejemplo de uso es pasar una ruta a un archivo de un usuario que usa otra configuración regional.

+1

La cuestión de codificación confundir las respuestas, sugiero un 'python3 argv.py \' echo -ne "\ xff \ x80 \ x00" \ '' que es un ejemplo de «pasar datos binarios mediante argumentos de línea de comandos» – Nope

Respuesta

2

que puede hacer:

sys.argv[1].encode() o, si conoce la codificación utilizan como argumento o llame bytes(sys.argv[1], 'latin-1').

Ambos deberían darle una representación de bytes de la cadena Unicode.

De manera predeterminada, Python3 usa UTF-8.

+2

No, Python no necesariamente usa UTF8, depende de la plataforma. –

+2

@Lennart Python 3 usa UTF-8 como codificación predeterminada. – JBernardo

+2

No, no es tan simple. La codificación predeterminada para los terminales no es necesariamente UTF-8 y tampoco es la codificación predeterminada para los sistemas de archivos.Cito "Existe una codificación predeterminada dependiente de la plataforma, que en plataformas Unixy se puede establecer con la variable de entorno LANG (y a veces también con algunas otras variables de entorno relacionadas con la configuración regional específica de la plataforma). En muchos casos, pero no en todos, el valor predeterminado del sistema es UTF-8; nunca debe contar con este valor predeterminado ". De hecho, es cp1252 el predeterminado en Windows. Sin embargo, el valor predeterminado para los archivos .py es UTF8. –

8

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

La mejor manera de lidiar con esto es utilizar los conocimientos a nivel de aplicación de la codificación correcta para reinterpretar el argumento de línea de comandos dentro de la aplicación, como en el siguiente ejemplo de código:

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

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

os.fsencode se añadió en Python 3.2, específicamente para hacer que este tipo de problema sea más fácil de tratar. Para Python 3.1, el constructo equivalente para os.fsencode(sys.argv[1]) es sys.argv[1].encode(sts.getfilesystemencoding(), 'surrogateescape')

Editar Feb 2013: actualizado para Python 3.2+, y para evitar el supuesto de que Python autodetectado "UTF-8", como la línea de comandos de codificación

+0

No puede suponer que la configuración regional es UTF-8. Por lo tanto, debe codificar utilizando la codificación del sistema de archivos: sys.argv [1] .encode (sys.getfilesystemencoding(), 'surrogateescape'). Decode ('latin-1') – mhagger

+2

De hecho. Aunque, en Python 3.3, usar 'os.fsencode' es aún más fácil. También archivé un error, señalando que los documentos sys.argv en realidad deberían explicar este punto. – ncoghlan

Cuestiones relacionadas