Zmiana domyślnego kodowania Pythona?

Mam wiele problemów z" Can ' t encode "I" can 't decode" z Pythonem kiedy uruchamiam moje aplikacje z konsoli. Ale w zaćmieniu PyDev IDE, domyślne kodowanie znaków jest ustawione na UTF-8 , i nic mi nie jest.

Szukałem wokół ustawiania domyślnego kodowania i ludzie mówią, że Python usuwa funkcję sys.setdefaultencoding przy starcie, i nie możemy jej użyć.

Więc jakie jest na to najlepsze rozwiązanie?

Author: Peter Mortensen, 2010-02-16

11 answers

Oto prostsza metoda (hack), która zwraca setdefaultencoding() funkcję, która została usunięta z sys:

import sys
# sys.setdefaultencoding() does not exist, here!
reload(sys)  # Reload does the trick!
sys.setdefaultencoding('UTF8')

(Uwaga dla Pythona 3.4+: reload() znajduje się w bibliotece importlib.)

Nie jest to jednak bezpieczna rzecz do zrobienia: jest to oczywiście hack, ponieważ sys.setdefaultencoding() jest celowo usuwany z sys podczas uruchamiania Pythona. Ponowne włączenie go i zmiana domyślnego kodowania może złamać kod, który polega na tym, że ASCII jest domyślnym (kod ten może być stroną trzecią, co z reguły uniemożliwiają lub są niebezpieczne).

 168
Author: Eric O Lebigot,
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
2020-03-01 09:07:46

Jeśli pojawi się ten błąd podczas próby przekierowania/przekierowania wyjścia skryptu

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)

Po prostu Eksportuj PYTHONIOENCODING w konsoli, a następnie uruchom kod.

export PYTHONIOENCODING=utf8

 79
Author: iman,
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
2014-11-21 16:33:51

A) do sterowania sys.getdefaultencoding() Wyjście:

python -c 'import sys; print(sys.getdefaultencoding())'

ascii

Then

echo "import sys; sys.setdefaultencoding('utf-16-be')" > sitecustomize.py

I

PYTHONPATH=".:$PYTHONPATH" python -c 'import sys; print(sys.getdefaultencoding())'

utf-16-be

Możesz umieścić swoje sitecustomize.py wyżej w Twoim PYTHONPATH.

Również możesz spróbować reload(sys).setdefaultencoding by @EOL

B) do sterowania stdin.encoding i stdout.encoding chcesz ustawić PYTHONIOENCODING:

python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'

ascii ascii

Then

PYTHONIOENCODING="utf-16-be" python -c 'import sys; 
print(sys.stdin.encoding, sys.stdout.encoding)'

utf-16-be utf-16-be

Wreszcie: możesz użyć A) lub B) lub oba!

 53
Author: lukmdo,
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-05-23 11:55:01

Począwszy od PyDev 3.4.1, domyślne kodowanie nie jest już zmieniane. Zobacz ten bilet Po szczegóły.

Dla starszych wersji rozwiązaniem jest upewnienie się, że PyDev nie działa z UTF-8 jako domyślnym kodowaniem. Pod Eclipse uruchom Ustawienia dialogowe ("Uruchom konfiguracje", jeśli dobrze pamiętam); możesz wybrać domyślne kodowanie na karcie common. Zmień go na US-ASCII, jeśli chcesz mieć te błędy "wcześnie" (innymi słowy: w środowisku PyDev). Zobacz również oryginalny wpis na blogu dla tego obejścia .

 18
Author: ChristopheD,
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
2014-11-11 18:47:54

Jeśli chodzi o python2 (i tylko python2), niektóre z poprzednich odpowiedzi polegają na użyciu następującego hack:

import sys
reload(sys)  # Reload is a hack
sys.setdefaultencoding('UTF8')

Odradza się korzystanie z niego (sprawdź to lub to)

W moim przypadku ma to efekt uboczny: używam notebooków ipython, a po uruchomieniu kodu funkcja drukowania nie działa. Myślę, że nie byłoby rozwiązanie, ale nadal myślę, że za pomocą hack nie powinno być właściwą opcją.

Po wypróbowaniu wielu opcji, ta, która dla mnie było użycie tego samego kodu w sitecustomize.py, Gdzie ten fragment kodu ma być. Po ocenie tego modułu funkcja setdefaultencoding jest usuwana z sys.

Więc rozwiązaniem jest dodanie do pliku /usr/lib/python2.7/sitecustomize.py kodu:

import sys
sys.setdefaultencoding('UTF8')

Kiedy używam virtualenvwrapper plik, który edytuję to ~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py.

A kiedy używam z notebookami Pythona i conda, to jest ~/anaconda2/lib/python2.7/sitecustomize.py

 13
Author: kiril,
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-05-23 12:02:57

Jest wnikliwy wpis na blogu o tym.

Zobacz https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/.

Parafrazuję jego treść poniżej.

W Pythonie 2, który nie był tak mocno napisany w odniesieniu do kodowania łańcuchów, można było wykonywać operacje na inaczej zakodowanych łańcuchach i odnieść sukces. Np. zwróci się True.

u'Toshio' == 'Toshio'

, który przechowywałby każdy (normalny, niezakodowany) ciąg znaków, który został zakodowany w sys.getdefaultencoding(), które domyślnie ascii, ale nie inne.

Domyślne kodowanie miało zostać zmienione w całym systemie w site.py, ale nie gdzie indziej. Hacki (również przedstawione tutaj), aby ustawić go w modułach użytkownika były po prostu takie: hacki, Nie rozwiązanie.

Python 3 zmienił kodowanie systemowe na domyślne utf-8 (gdy LC_CTYPE jest świadomy unicode), ale podstawowy problem został rozwiązany z wymogiem jawnego kodowania łańcuchów "bajtów", gdy są one używane z unicode struny.

 8
Author: ibotty,
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
2015-06-17 09:37:58

Po pierwsze: reload(sys) i ustawianie domyślnego kodowania przypadkowego tylko w związku z potrzebą strumienia terminala wyjściowego jest złą praktyką. reload często zmienia rzeczy w sys, które zostały wprowadzone w zależności od środowiska - np. sys.strumienie stdin / stdout, sys.excepthook itp.

Rozwiązywanie problemu z kodowaniem na stdout

Najlepsze rozwiązanie jakie znam do rozwiązania problemu kodowania print'ING Unicode strings and beyond-ascii str's (np. z literałów) na sys.stdout to: to zajmij się sys.stdout (obiekt podobny do pliku), który jest zdolny i opcjonalnie tolerancyjny w odniesieniu do potrzeb:

  • Jeśli sys.stdout.encoding jest None z jakiegoś powodu, nieistniejące, błędnie fałszywe lub "mniej" niż to, do czego terminal lub strumień stdout jest zdolny, spróbuj podać poprawny atrybut .encoding. W końcu poprzez zastąpienie sys.stdout & sys.stderr przez obiekt podobny do pliku.

  • Gdy terminal / stream nadal nie może zakodować wszystkich występujących znaków unicode, a gdy nie chcesz łamać print tylko z tego powodu możesz wprowadzić zachowanie encode-with-replace w obiekcie podobnym do pliku.

Oto przykład:

#!/usr/bin/env python
# encoding: utf-8
import sys

class SmartStdout:
    def __init__(self, encoding=None, org_stdout=None):
        if org_stdout is None:
            org_stdout = getattr(sys.stdout, 'org_stdout', sys.stdout)
        self.org_stdout = org_stdout
        self.encoding = encoding or \
                        getattr(org_stdout, 'encoding', None) or 'utf-8'
    def write(self, s):
        self.org_stdout.write(s.encode(self.encoding, 'backslashreplace'))
    def __getattr__(self, name):
        return getattr(self.org_stdout, name)

if __name__ == '__main__':
    if sys.stdout.isatty():
        sys.stdout = sys.stderr = SmartStdout()

    us = u'aouäöüфżß²'
    print us
    sys.stdout.flush()

Używanie poza-ascii zwykłych literałów łańcuchowych w Pythonie 2 / 2 + 3 kod

Jedyny dobry powód, aby zmienić globalne domyślne kodowanie (tylko UTF-8), myślę, że dotyczy decyzji aplikacji kod źródłowy - a nie z powodu problemów z kodowaniem strumieni We/Wy: do pisania poza-ascii literały ciągów znaków w kodzie bez zmuszania do używania Unikodu w stylu u'string'. Można to zrobić dość konsekwentnie (pomimo tego, co mówi artykuł anonbadger), opierając się na kodzie źródłowym Pythona 2 lub Pythona 2 + 3, który konsekwentnie używa znaków ASCII lub UTF-8 - o ile te łańcuchy potencjalnie przechodzą cichą konwersję unicode i poruszają się między modułami lub potencjalnie przechodzą na stdout. W tym celu wybierz "# encoding: utf-8 " lub ascii (bez deklaracji). Zmień lub upuść biblioteki, które nadal w bardzo głupi sposób polegają na domyślnych błędach kodowania ascii poza chr #127 (co jest dziś rzadkością).

I zrób tak przy starcie aplikacji (i / lub poprzez sitecustomize.py) oprócz powyższego schematu SmartStdout - bez użycia reload(sys):

...
def set_defaultencoding_globally(encoding='utf-8'):
    assert sys.getdefaultencoding() in ('ascii', 'mbcs', encoding)
    import imp
    _sys_org = imp.load_dynamic('_sys_org', 'sys')
    _sys_org.setdefaultencoding(encoding)

if __name__ == '__main__':
    sys.stdout = sys.stderr = SmartStdout()
    set_defaultencoding_globally('utf-8') 
    s = 'aouäöüфżß²'
    print s

W ten sposób literały łańcuchowe i większość operacji (poza iteracją znaków) działają komfortowo bez myślenia o konwersji unicode, tak jakby było tylko Python3. Plik I/O oczywiście zawsze należy zwrócić szczególną uwagę na kodowanie-tak jak w Python3.

Uwaga: ciągi równin są następnie implicially konwertowane z utf-8 do unicode w SmartStdout przed konwertowaniem do strumienia wyjściowego enconding.

 4
Author: kxr,
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-04-27 10:53:27

Oto podejście, którego użyłem do wytworzenia kodu, który był kompatybilny zarówno z python2i python3i zawsze produkował utf8 wyjście. Znalazłem tę odpowiedź gdzie indziej, ale nie pamiętam źródła.

To podejście działa poprzez zastąpienie sys.stdout czymś, co nie jest całkiem podobne do pliku (ale nadal używa tylko rzeczy w bibliotece standardowej). Może to również powodować problemy dla bazowych bibliotek, ale w prostym przypadku, gdy masz dobrą kontrolę nad tym, jak sys.stdout out jest używany przez twój framework może to być rozsądne podejście.

sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')
 4
Author: Att Righ,
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-05-25 20:50:07

Jest to szybki hack dla każdego, kto jest (1) na platformie Windows (2) z Pythonem 2.7 i (3) zirytowany, ponieważ ładny kawałek oprogramowania (tzn. nie napisany przez Ciebie, więc nie od razu kandydat do kodowania / dekodowania manewrów drukowania)nie wyświetla "ładnych znaków unicode" w bezczynnym środowisku( Pythonwin drukuje Unicode fine), na przykład, schludne symbole logiki pierwszego rzędu, które Stephan Boyer używa w wyjściu z jego pedagogic prover w logiki pierwszego rzędu Prover .

Nie spodobał mi się pomysł wymuszenia przeładowania sys i nie mogłem zmusić systemu do współpracy z ustawianiem zmiennych środowiskowych, takich jak PYTHONIOENCODING (próbowałem bezpośredniej zmiennej środowiskowej Windows, a także upuszczając ją w sitecustomize.py in site-packages as a one liner ='utf-8').

Tak więc, jeśli chcesz zhakować swoją drogę do sukcesu, przejdź do swojego bezczynnego katalogu, zazwyczaj: "C:\Python27\Lib\idlelib" Zlokalizuj plik IOBinding.py. zrób kopię tego pliku i przechowuj go gdzie indziej, dzięki czemu możesz powrócić do oryginalnego zachowania, gdy wybierzesz. Otwórz plik w idlelib za pomocą edytora (np. IDLE). Przejdź do tego obszaru kodu:

# Encoding for file names
filesystemencoding = sys.getfilesystemencoding()

encoding = "ascii"
if sys.platform == 'win32':
    # On Windows, we could use "mbcs". However, to give the user
    # a portable encoding name, we need to find the code page 
    try:
        # --> 6/5/17 hack to force IDLE to display utf-8 rather than cp1252
        # --> encoding = locale.getdefaultlocale()[1]
        encoding = 'utf-8'
        codecs.lookup(encoding)
    except LookupError:
        pass

Innymi słowy, skomentuj oryginalny wiersz kodu następujący po ' try ', który sprawiał, że zmienna kodująca była równa ustawieniu locale .getdefaultlocale (ponieważ to da ci cp1252, którego nie chcesz) i zamiast tego brutalnie wymusić go na' utf-8 '(dodając linię 'encoding = ' utf-8', Jak pokazano).

Uważam, że dotyczy to tylko bezczynnego wyświetlania na stdout, a nie kodowania używanego do nazw plików itp. (które jest uzyskiwane w systemie plików przed kodowaniem). Jeśli masz problem z innym kodem, który uruchomisz w IDLE później, po prostu wymień IOBinding.py Plik z oryginalnym niezmodyfikowanym plikiem.

 2
Author: Dalton Bentley,
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-06-05 23:41:02

To naprawiło problem dla mnie.

import os
os.environ["PYTHONIOENCODING"] = "utf-8"
 1
Author: twasbrillig,
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-12 21:38:57

Możesz zmienić kodowanie całego systemu operacyjnego. na Ubuntu możesz to zrobić z

sudo apt install locales 
sudo locale-gen en_US en_US.UTF-8    
sudo dpkg-reconfigure locales
 1
Author: Boris,
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
2020-02-17 18:41:38