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")
Author: smci, 2010-09-30

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:

 125
Author: pyfunc,
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?

sys.setdefaultencoding("utf-8") (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:

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)

sys.setdefaultencoding("utf-8") 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

Konsola

sys.setdefaultencoding("utf-8") ma również efekt uboczny pojawiania się poprawki 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

 43
Author: Alastair McCormack,
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ć

 17
Author: Sérgio,
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ściwe

    Wszystko, 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.)
 3
Author: ivan_pozdeev,
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