Widziałem kilka skryptów py, które używają tego na początku skryptu. W jakich przypadkach należy go używać?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Widziałem kilka skryptów py, które używają tego na początku skryptu. W jakich przypadkach należy go używać?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Odpowiedzi:
Zgodnie z dokumentacją: Pozwala to na przełączenie się z domyślnego ASCII na inne kodowanie, takie jak UTF-8, którego środowisko wykonawcze Pythona będzie używać, gdy będzie musiało zdekodować bufor ciągów na Unicode.
Ta funkcja jest dostępna tylko podczas uruchamiania Pythona, kiedy Python skanuje środowisko. Należy go wywołać w module ogólnosystemowym. sitecustomize.py
Po ocenie tego modułu setdefaultencoding()
funkcja jest usuwana z sys
modułu.
Jedynym sposobem faktycznego użycia tego atrybutu jest hack przeładowania, który przywraca atrybut.
Ponadto, używanie sys.setdefaultencoding()
zawsze było odradzane i stało się opcją w py3k. Kodowanie py3k jest na stałe połączone z „utf-8”, a jego zmiana powoduje błąd.
Proponuję kilka wskazówek do czytania:
sys.stdout
gdy ma None
kodowanie, na przykład podczas przekierowywania wyjścia programu w Pythonie).
sys.setdefaultencoding()
zawsze było odradzane”
UTF-8
. LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'
daje, UTF-8
ale LC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'
daje ANSI_X3.4-1968
(a może coś innego)
Odpowiedź brzmi: NIGDY ! (chyba że naprawdę wiesz, co robisz)
9/10 razy rozwiązanie można rozwiązać przy odpowiednim zrozumieniu kodowania / dekodowania.
1/10 osób ma nieprawidłowo zdefiniowaną lokalizację lub środowisko i musi ustawić:
PYTHONIOENCODING="UTF-8"
w ich środowisku, aby naprawić problemy z drukowaniem konsoli.
(przekreślony, aby uniknąć ponownego użycia) zmienia domyślne kodowanie / dekodowanie używane zawsze, gdy Python 2.x musi przekonwertować Unicode () na str () (i odwrotnie), a kodowanie nie jest podane. To znaczy:sys.setdefaultencoding("utf-8")
str(u"\u20AC")
unicode("€")
"{}".format(u"\u20AC")
W Pythonie 2.x domyślne kodowanie jest ustawione na ASCII, a powyższe przykłady zakończą się niepowodzeniem z:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
(Moja konsola jest skonfigurowana jako UTF-8, więc "€" = '\xe2\x82\xac'
wyjątek włączony \xe2
)
lub
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
pozwoli im działać dla mnie , ale niekoniecznie będzie działać dla osób, które nie używają UTF-8. Domyślne ASCII zapewnia, że założenia kodowania nie są wprowadzane do kodusys.setdefaultencoding("utf-8")
ma również efekt uboczny polegający na poprawianiu sys.setdefaultencoding("utf-8")
sys.stdout.encoding
, używanym podczas drukowania znaków na konsoli. Python używa ustawień regionalnych użytkownika (Linux / OS X / Un * x) lub strony kodowej (Windows), aby to ustawić. Czasami ustawienia regionalne użytkownika są zepsute i wymagają tylko PYTHONIOENCODING
naprawy kodowania konsoli .
Przykład:
$ 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"
€
Od 16 lat ludzie rozwijają się przeciwko Pythonowi 2.x, wiedząc, że domyślnym kodowaniem jest ASCII. UnicodeError
metody obsługi wyjątków zostały napisane w celu obsługi konwersji ciągów na Unicode w ciągach, które zawierają inne niż ASCII.
Od 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"))
Przed ustawieniem domyślnego kodowania ten kod nie byłby w stanie zdekodować „Å” w kodowaniu ascii, a następnie wprowadziłby procedurę obsługi wyjątku, aby odgadnąć kodowanie i poprawnie przekształcić go w Unicode. Drukowanie: Angstrom (Å®) prowadzi Twoją firmę. Po ustawieniu domyślnego kodowania na utf-8, kod stwierdzi, że bajt_string można zinterpretować jako utf-8, więc zmieni dane i zwróci to: Angstrom (Ů) prowadzi Twoją firmę.
Zmiana tego, co powinno być stałą, będzie miała dramatyczny wpływ na moduły, na których polegasz. Lepiej jest po prostu naprawić dane przychodzące i wychodzące z kodu.
Chociaż ustawienie domyślnego kodowania na UTF-8 nie jest główną przyczyną w poniższym przykładzie, pokazuje, jak problemy są maskowane i jak, gdy zmienia się kodowanie wejściowe, kod psuje się w nieoczywisty sposób: UnicodeDecodeError: kodek 'utf8' może 't dekoduj bajt 0x80 na pozycji 3131: nieprawidłowy bajt początkowy
sys.setdefaultencoding("utf-8")
nim niespodzianki , dobrze jest sprawić, by kod zachowywał się bardziej jak Python 3. Teraz jest rok 2017. Nawet jeśli napisałeś odpowiedź w 2015 roku, myślę, że już lepiej było patrzeć w przyszłość niż w przeszłość. To było dla mnie najprostsze rozwiązanie, gdy zauważyłem, że mój kod zachowuje się inaczej w Pythonie 2 w zależności od tego, czy dane wyjściowe są przekierowywane (bardzo nieprzyjemny problem dla Pythona 2). Nie trzeba dodawać, że już mam # coding: utf-8
i nie potrzebuję żadnych obejść dla Pythona 3 (właściwie muszę zamaskować setdefaultencoding
sprawdzanie wersji przy użyciu).
sys.setdefaultencoding("utf-8")
nie sprawia, że kod Py 2.x jest zgodny z Pythonem 3. Nie naprawia też zewnętrznych modułów, które zakładają, że domyślnym kodowaniem jest ASCII. Dostosowanie kodu do Pythona 3 jest bardzo proste i nie wymaga tego okropnego hackowania. Na przykład, dlaczego powoduje to bardzo realne problemy, zobacz moje doświadczenia z Amazon mieszające się z tym założeniem: stackoverflow.com/questions/39465220/ ...
PYTHONIOENCODING="UTF-8"
pomogło mojemu środowisku Python2.7 Django-1.11. Dzięki.
detect_encoding
.
detect_encoding
jest to metoda, która mogłaby wykryć kodowanie łańcucha na podstawie wskazówek językowych.
#!/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)
w powłoce działa, wysyłanie do sdtout nie, więc jest to jedno obejście, aby pisać na standardowe wyjście.
Zrobiłem inne podejście, które nie jest uruchamiane, jeśli sys.stdout.encoding nie jest zdefiniowane, lub innymi słowy, musisz najpierw wyeksportować PYTHONIOENCODING = UTF-8, aby zapisać na standardowe wyjście.
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)
więc, używając tego samego przykładu:
export PYTHONIOENCODING=UTF-8
./test.py > output.txt
będzie działać
Pierwsze niebezpieczeństwo tkwi w reload(sys)
.
Kiedy przeładowujesz moduł, w rzeczywistości otrzymujesz dwie kopie modułu w swoim środowisku wykonawczym. Stary moduł jest obiektem Pythona, jak wszystko inne, i pozostaje żywy, dopóki istnieją do niego odniesienia. Tak więc połowa obiektów będzie wskazywała na stary moduł, a połowa na nowy. Kiedy wprowadzisz jakąś zmianę, nigdy nie zobaczysz, że nadchodzi, gdy jakiś losowy obiekt nie zauważy zmiany:
(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>
Teraz sys.setdefaultencoding()
dobrze
Wszystko, na co ma wpływ, to niejawna konwersjastr<->unicode
. Czy utf-8
jest to najbardziej rozsądne kodowanie na tej planecie (kompatybilne wstecz z ASCII i wszystkimi innymi), konwersja „po prostu działa”, co może się nie udać?
Cóż, wszystko. I to jest niebezpieczeństwo.
UnicodeError
wyrzucaniu dla danych wejściowych innych niż ASCII lub transkodowanie z obsługą błędów, co teraz daje nieoczekiwany wynik. A ponieważ cały kod jest testowany z ustawieniem domyślnym, jesteś tutaj ściśle na „nieobsługiwanym” terytorium i nikt nie daje Ci gwarancji, jak będzie się zachowywał jego kod.