Ho visto alcuni script Py che usano questo nella parte superiore dello script. In quali casi si dovrebbe usarlo?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Ho visto alcuni script Py che usano questo nella parte superiore dello script. In quali casi si dovrebbe usarlo?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Risposte:
Come da documentazione: questo ti permette di passare dall'ASCII predefinito ad altre codifiche come UTF-8, che il runtime di Python utilizzerà ogni volta che dovrà decodificare un buffer di stringa in Unicode.
Questa funzione è disponibile solo al momento dell'avvio di Python, quando Python esegue la scansione dell'ambiente. Deve essere chiamato in un modulo a livello di sistema sitecustomize.py
, dopo che questo modulo è stato valutato, la setdefaultencoding()
funzione viene rimossa dal sys
modulo.
L'unico modo per usarlo effettivamente è con un hack di ricarica che riporta l'attributo.
Inoltre, l'uso di sys.setdefaultencoding()
è sempre stato scoraggiato , ed è diventato una no-op in py3k. La codifica di py3k è cablata su "utf-8" e la sua modifica genera un errore.
Suggerisco alcuni suggerimenti per la lettura:
sys.stdout
quando ha una None
codifica, come quando si reindirizza l'output di un programma Python).
sys.setdefaultencoding()
è sempre stato scoraggiato"
UTF-8
. LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'
dà UTF-8
ma LC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'
dà ANSI_X3.4-1968
(o forse qualcos'altro)
La risposta è MAI ! (a meno che tu non sappia davvero cosa stai facendo)
9/10 volte la soluzione può essere risolta con una corretta comprensione della codifica / decodifica.
1/10 persone hanno una locale o un ambiente definiti in modo errato e devono impostare:
PYTHONIOENCODING="UTF-8"
nel loro ambiente per risolvere i problemi di stampa della console.
(barrato per evitare il riutilizzo) modifica la codifica / decodifica predefinita utilizzata ogni volta che Python 2.x deve convertire un Unicode () in uno str () (e viceversa) e la codifica non viene fornita. Vale a dire:sys.setdefaultencoding("utf-8")
str(u"\u20AC")
unicode("€")
"{}".format(u"\u20AC")
In Python 2.x, la codifica predefinita è impostata su ASCII e gli esempi sopra non riusciranno con:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
(La mia console è configurata come UTF-8, quindi "€" = '\xe2\x82\xac'
, quindi eccezione su \xe2
)
o
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
permetterà a questi di funzionare per me , ma non funzionerà necessariamente per le persone che non usano UTF-8. L'impostazione predefinita di ASCII garantisce che i presupposti della codifica non vengano inseriti nel codicesys.setdefaultencoding("utf-8")
ha anche un effetto collaterale di apparire da correggere sys.setdefaultencoding("utf-8")
sys.stdout.encoding
, usato quando si stampano i caratteri sulla console. Python utilizza le impostazioni locali dell'utente (Linux / OS X / Un * x) o la tabella codici (Windows) per impostarle. Occasionalmente, la localizzazione di un utente viene interrotta e richiede solo PYTHONIOENCODING
di correggere la codifica della console .
Esempio:
$ 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"
€
Le persone hanno sviluppato Python 2.x per 16 anni con la consapevolezza che la codifica predefinita è ASCII. UnicodeError
sono stati scritti metodi di gestione delle eccezioni per gestire le conversioni da stringa a Unicode su stringhe che non contengono ASCII.
Da 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"))
Prima di impostare la codifica predefinita, questo codice non sarebbe stato in grado di decodificare "Å" nella codifica ASCII e quindi inserire il gestore eccezioni per indovinare la codifica e trasformarla correttamente in Unicode. Stampa: Angstrom (Å®) gestisce la tua attività. Dopo aver impostato la codifica predefinita su utf-8, il codice troverà che byte_string può essere interpretato come utf-8 e quindi manipolerà i dati e lo restituirà invece: Angstrom (Ů) gestisce la tua attività.
Cambiare quella che dovrebbe essere una costante avrà effetti drammatici sui moduli da cui dipendi. È meglio semplicemente correggere i dati in entrata e in uscita dal codice.
Mentre l'impostazione della codifica predefinita su UTF-8 non è la causa principale nell'esempio seguente, mostra come vengono mascherati i problemi e come, quando cambia la codifica di input, il codice si interrompe in modo non visibile: UnicodeDecodeError: il codec 'utf8' può decodifica byte 0x80 in posizione 3131: byte iniziale non valido
sys.setdefaultencoding("utf-8")
, è bene far sì che il codice si comporti più come Python 3. È il 2017 ora. Anche quando hai scritto la risposta nel 2015, penso che fosse già meglio guardare avanti anziché indietro. In realtà è stata la soluzione più semplice per me, quando ho scoperto che il mio codice si comportava diversamente in Python 2 a seconda che l'output fosse reindirizzato (problema molto brutto per Python 2). Inutile dire che l'ho già fatto # coding: utf-8
e non ho bisogno di soluzioni alternative per Python 3 (in realtà devo mascherare il setdefaultencoding
controllo della versione usando).
sys.setdefaultencoding("utf-8")
non rende il tuo codice Py 2.x compatibile con Python 3. Né corregge i moduli esterni che presuppongono che la codifica predefinita sia ASCII. Rendere compatibile il tuo codice Python 3 è molto semplice e non richiede questo brutto hack. Ad esempio perché questo causa problemi molto reali, vedi la mia esperienza con Amazon che scherza con questo presupposto: stackoverflow.com/questions/39465220/…
PYTHONIOENCODING="UTF-8"
aiutato il mio ambiente Python2.7 Django-1.11. Grazie.
detect_encoding
.
detect_encoding
sia un metodo in grado di rilevare la codifica di una stringa in base agli indizi del linguaggio.
#!/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)
su shell funziona, inviando a sdtout no, quindi questa è una soluzione alternativa, per scrivere su stdout.
Ho adottato un altro approccio, che non viene eseguito se sys.stdout.encoding non è definito, o in altre parole, è necessario prima esportare PYTHONIOENCODING = UTF-8 per scrivere su 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)
quindi, usando lo stesso esempio:
export PYTHONIOENCODING=UTF-8
./test.py > output.txt
funzionerà
Il primo pericolo sta dentro reload(sys)
.
Quando ricarichi un modulo, ottieni effettivamente due copie del modulo nel tuo runtime. Il vecchio modulo è un oggetto Python come tutto il resto, e rimane in vita finché ci sono riferimenti ad esso. Quindi, metà degli oggetti punta al vecchio modulo e metà a quello nuovo. Quando fai qualche cambiamento, non lo vedrai mai arrivare quando un oggetto casuale non vede il cambiamento:
(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>
Ora, sys.setdefaultencoding()
la corretta
Tutto ciò che colpisce è la conversione implicitastr<->unicode
. Ora, utf-8
la codifica più sana del pianeta (retrocompatibile con ASCII e tutte), la conversione ora "funziona", cosa potrebbe andare storto?
Bene, qualunque cosa. E questo è il pericolo.
UnicodeError
lancio per input non ASCII o sulla transcodifica con un gestore di errori, che ora produce un risultato imprevisto. E poiché tutto il codice viene testato con le impostazioni predefinite, qui si è rigorosamente su territori "non supportati" e nessuno ti garantisce in che modo si comporterà il loro codice.