Dlaczego nie powinniśmy używać sys.setdefaultencoding ("utf-8") w skrypcie py?
Widziałem kilka skryptów py, które używają tego na górze skryptu. W jakich przypadkach należy go używać?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
4 answers
Zgodnie z dokumentacją: pozwala to na przełączenie się z domyślnego ASCII na inne kodowania, takie jak UTF-8, które środowisko uruchomieniowe Pythona będzie używać za każdym razem, gdy ma dekodować bufor łańcuchów znaków do unicode.
Ta funkcja jest dostępna tylko podczas uruchamiania Pythona, gdy Python skanuje środowisko. Należy ją wywołać w module systemowym, sitecustomize.py
, po ocenie tego modułu funkcja setdefaultencoding()
jest usuwana z modułu sys
.
Jedynym sposobem, aby go użyć jest z przeładowania hack, który przynosi atrybut z powrotem.
Również, używanie sys.setdefaultencoding()
zawsze było zniechęcane I stało się no-op w py3k. kodowanie py3k jest podłączone do "utf-8" i zmiana powoduje błąd.
Proponuję kilka wskazówek dla czytanie:
- http://blog.ianbicking.org/illusive-setdefaultencoding.html
- http://nedbatchelder.com/blog/200401/printing_unicode_from_python.html
- http://www.diveintopython3.net/strings.html#one-ring-to-rule-them-all
- http://boodebr.org/main/python/all-about-python-and-unicode
- http://blog.notdot.net/2010/07/Getting-unicode-right-in-Python
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-13 21:59:12
Tl;dr
Odpowiedź brzmi nigdy ! (chyba, że naprawdę wiesz, co robisz)
9/10 razy rozwiązanie może być rozwiązane przy odpowiednim zrozumieniu kodowania/dekodowania.
1/10 osób ma niepoprawnie zdefiniowane locale lub środowisko i musi ustawić:
PYTHONIOENCODING="UTF-8"
W ich środowisku, aby rozwiązać problemy z drukowaniem konsoli.
Co to robi?
(przebite, aby uniknąć ponownego użycia) zmienia domyślną kodowanie / dekodowanie używane w Pythonie 2.x musi przekonwertować Unicode () na str() (i odwrotnie), a kodowanie nie jest podane. I. E: 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 zawiodą:
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'
, stąd wyjątek na \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ślna wartość ASCII gwarantuje, że założenia kodowania nie zostaną zapisane w kodzie sys.setdefaultencoding("utf-8")
Konsola
ma również efekt uboczny pojawiania się poprawki sys.setdefaultencoding("utf-8")
sys.stdout.encoding
, używanej 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ą łamane i po prostu wymaga PYTHONIOENCODING
, aby naprawić kodowanie 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"
€
Co jest tak źle z sys.setdefaultencoding ("utf-8")?
Ludzie rozwijają się przeciwko Pythonowi 2.x przez 16 lat ze zrozumieniem, że domyślnym kodowaniem jest ASCII. UnicodeError
metody obsługi wyjątków zostały napisane do obsługi konwersji łańcuchów znaków na Unicode na łańcuchach, które zawierają znaki 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"))
Poprzednia do ustawienia domyślnego kodowania kod ten nie byłby w stanie dekodować "Å" w kodowaniu ascii, a następnie wprowadzałby obsługę wyjątków, aby odgadnąć kodowanie i odpowiednio przekształcić je w unicode. Drukowanie: Angstrom (Å®) prowadzi Twoją firmę. Po ustawieniu domyślnego kodowania na utf - 8, kod okaże się, że byte_string może być interpretowany jako utf-8, a więc będzie mangle danych i zwróci to zamiast: Angstrom (Ů) prowadzi Twoją firmę.
Zmiana tego, co powinno być stałą, będzie miała dramatyczny wpływ na moduły, od których zależą. Lepiej po prostu naprawić dane wchodzące i wychodzące z kodu.
Przykładowy problem
Podczas gdy 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 kodowanie wejściowe zmienia się, kod łamie się w nieoczywisty sposób: UnicodeDecodeError: kodek 'utf8' nie może dekodować bajtu 0x80 w pozycji 3131: invalid start byte
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-03 12:52:34
#!/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)
Na Shell działa, wysyłanie do sdtout nie , więc jest to jedno obejście, aby napisać do stdout .
Zrobiłem inne podejście, które nie jest uruchamiane, jeśli sys.stdout.kodowanie nie jest definiowane, lub innymi słowy, należy najpierw wyeksportować PYTHONIOENCODING = UTF-8, aby zapisać na 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)
tak więc, używając tego samego przykładu:
export PYTHONIOENCODING=UTF-8
./test.py > output.txt
Będzie działać
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-19 03:50:16
-
Pierwsze niebezpieczeństwo leży w
reload(sys)
.Kiedy przeładowujesz moduł, otrzymujesz dwie kopie modułu w swoim środowisku uruchomieniowym. Stary moduł jest obiektem Pythona, jak Wszystko inne i pozostaje przy życiu tak długo, jak istnieją odniesienia do niego. Połowa obiektów będzie wskazywała na stary moduł, a połowa na nowy. Kiedy dokonasz jakiejś zmiany, nigdy jej nie zauważysz, gdy jakiś przypadkowy obiekt nie zobaczy zmiana:
(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()
właściweWszystko, na co wpływa, to konwersja ukryta
str<->unicode
. Teraz,utf-8
jest najzdrowszym kodowaniem na świecie (wstecznie kompatybilnym z ASCII i wszystkimi), konwersja teraz "działa", co może pójść nie tak?Cokolwiek. I na tym polega niebezpieczeństwo.
- może być jakiś kod, który polega na rzuceniu
UnicodeError
dla wejścia nie-ASCII, lub transkodowanie z błędem handler, co daje teraz nieoczekiwany rezultat. I ponieważ cały kod jest testowany z domyślnym ustawieniem, jesteś wyłącznie na" nieobsługiwanym " terytorium i nikt nie daje Ci gwarancji, jak ich kod będzie się zachowywał. - transkodowanie może przynieść nieoczekiwane lub bezużyteczne wyniki, jeśli nie wszystko w systemie używa UTF-8 , ponieważ Python 2 faktycznie ma wiele niezależnych "domyślnych kodowań ciągów" . (Pamiętaj, że program musi działać dla klienta, na sprzęt klienta.)
- najgorsze jest to, że nigdy się tego nie dowiesz ponieważ nawrócenie jest niejawne - tak naprawdę nie wiesz, kiedy i gdzie to się dzieje. (Python Zen, koan 2 ahoj!) Nigdy nie dowiesz się, dlaczego (i czy) Twój kod działa na jednym systemie i łamie się na innym. (Albo jeszcze lepiej, działa w IDE i łamie w konsoli.)
- może być jakiś kod, który polega na rzuceniu
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-22 19:24:16