Mam wiele problemów „nie mogę zakodować” i „nie mogę dekodować” w Pythonie, kiedy uruchamiam swoje aplikacje z konsoli. Ale w Eclipse PyDev IDE domyślne kodowanie znaków jest ustawione na UTF-8 i wszystko w porządku.
Szukałem w pobliżu domyślnego kodowania, a ludzie mówią, że Python usuwa sys.setdefaultencoding
funkcję przy starcie i nie możemy jej używać.
Więc jakie jest na to najlepsze rozwiązanie?
The best solution is to learn to use encode and decode correctly instead of using hacks.
Było to z pewnością możliwe dzięki python2 kosztem ciągłego pamiętania o tym / konsekwentnego używania własnego interfejsu. Z mojego doświadczenia wynika, że staje się to bardzo problematyczne, gdy piszesz kod, z którym chcesz pracować zarówno z python2, jak i python3.Odpowiedzi:
Oto prostsza metoda (hack), która zwraca
setdefaultencoding()
funkcję, która została usunięta zsys
:(Uwaga dla Pythona 3.4+:
reload()
jest wimportlib
bibliotece.)Nie jest to jednak bezpieczna rzecz : jest to oczywiście hack, ponieważ
sys.setdefaultencoding()
jest celowo usuwanysys
podczas uruchamiania Pythona. Ponowne włączenie go i zmiana domyślnego kodowania może zepsuć kod, który opiera się na domyślnym ASCII (ten kod może być innej firmy, co generalnie uniemożliwiłoby lub byłoby niebezpieczne).źródło
LC_CTYPE
(lub w aplikacji sprawdzić, czy jest ustawiony prawidłowo i przerwać, wyświetlając znaczący komunikat o błędzie).LC_CTYPE=C python -c 'import locale; print( locale.getpreferredencoding())'
Jeśli pojawi się ten błąd podczas próby przesłania / przekierowania wyjścia skryptu
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
Po prostu wyeksportuj PYTHONIOENCODING w konsoli, a następnie uruchom kod.
export PYTHONIOENCODING=utf8
źródło
LC_CTYPE
Zamiast tego wybierz coś rozsądnego. To sprawia, że wszystkie inne programy są również szczęśliwe.PYTHONIOENCODING=utf8
nie jest to błąd domyślny. To sprawia, że skrypty psują się tylko dlatego, żeLC_ALL=C
Set LC_CTYPE to something sensible instead
To rozsądna sugestia. To nie działa tak dobrze, gdy próbujesz rozpowszechniać kod, który po prostu działa w systemie innej osoby.C.utf8
locale, aby zapewnić bardziej rozsądne ustawienia regionalne C. glibc pracuje nad dodaniem go, więc może nie powinniśmy winić Pythona za przestrzeganie ustawień regionalnych \…?A) Aby sterować
sys.getdefaultencoding()
wyjściem:ascii
Następnie
i
utf-16-be
Możesz umieścić plik sitecustomize.py wyżej w swoim
PYTHONPATH
.Możesz także spróbować
reload(sys).setdefaultencoding
przez @EOLB) Aby kontrolować
stdin.encoding
istdout.encoding
chcesz ustawićPYTHONIOENCODING
:ascii ascii
Następnie
utf-16-be utf-16-be
Wreszcie: możesz użyć A) lub B) lub obu!
źródło
from __future__ import unicode_literals
patrz dyskusjaPocząwszy od PyDev 3.4.1, domyślne kodowanie nie jest już zmieniane. Zobacz ten bilet, aby uzyskać szczegółowe informacje.
W przypadku wcześniejszych wersji rozwiązaniem jest upewnienie się, że PyDev nie działa z kodowaniem UTF-8 jako domyślnym. Pod Eclipse uruchom ustawienia okna dialogowego („uruchom konfiguracje”, jeśli dobrze pamiętam); możesz wybrać domyślne kodowanie na wspólnej karcie. Zmień to na US-ASCII, jeśli chcesz mieć te błędy „wcześnie” (innymi słowy: w środowisku PyDev). Zobacz także oryginalny wpis na blogu dotyczący tego obejścia .
źródło
Jeśli chodzi o python2 (i tylko python2), niektóre z poprzednich odpowiedzi polegają na użyciu następującego hackowania:
Odradza się go używać (sprawdź to lub to )
W moim przypadku ma to efekt uboczny: używam notebooków ipython i po uruchomieniu kodu funkcja „print” przestaje działać. Myślę, że byłoby rozwiązanie tego problemu, ale nadal uważam, że użycie hacka nie powinno być właściwą opcją.
Po wypróbowaniu wielu opcji, ta, która działała dla mnie, polegała na użyciu tego samego kodu w miejscu
sitecustomize.py
, w którym powinien znajdować się ten fragment kodu . Po ocenie tego modułu funkcja setdefaultencoding jest usuwana z sys.Więc rozwiązaniem jest dołączenie do pliku
/usr/lib/python2.7/sitecustomize.py
kodu:Kiedy używam virtualenvwrapper, edytowany przeze mnie plik to
~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py
.A kiedy używam z notatnikami Pythona i conda, tak jest
~/anaconda2/lib/python2.7/sitecustomize.py
źródło
Jest na ten temat wnikliwy post na blogu.
Zobacz https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/ .
Poniżej parafrazuję jego treść.
W Pythonie 2, który nie był tak silnie wpisany pod względem kodowania ciągów, można było wykonywać operacje na inaczej zakodowanych łańcuchach i odnieść sukces. Np
True
. Wrócą następujące .To będzie obowiązywać dla każdego (normalnego, bez prefiksu) ciągu, który został zakodowany
sys.getdefaultencoding()
, który domyślnie był ustawiony naascii
, ale nie dla innych.Domyślne kodowanie miało zostać zmienione w całym systemie
site.py
, ale nie gdzie indziej. Hacki (również tutaj przedstawione), aby ustawić go w modułach użytkownika, były po prostu: hacki, a nie rozwiązanie.Python 3 zmienił kodowanie systemu na domyślne na utf-8 (gdy LC_CTYPE obsługuje Unicode), ale podstawowy problem został rozwiązany z wymogiem jawnego kodowania łańcuchów „bajtowych”, ilekroć są one używane z ciągami znaków Unicode.
źródło
Po pierwsze:
reload(sys)
a ustawienie jakiegoś losowego domyślnego kodowania tylko ze względu na 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. strumienie sys.stdin / stdout, sys.excepthook itp.Rozwiązanie problemu z kodowaniem na stdout
Najlepszym rozwiązaniem, jakie znam, aby rozwiązać problem z kodowaniem w przypadku
print
ciągów znaków Unicode i poza-asciistr
(np. Z literałów) na sys.stdout jest: zająć się sys.stdout (obiekt podobny do pliku), który jest zdolny i opcjonalnie tolerancyjny w stosunku do potrzeb:Kiedy
sys.stdout.encoding
jestNone
z jakiegoś powodu lub nie istnieje, błędnie fałszywe lub „mniejsze” niż to, do czego naprawdę jest zdolny terminal lub strumień standardowego strumienia, spróbuj podać poprawny.encoding
atrybut. W końcu zastępującsys.stdout & sys.stderr
go tłumaczącym obiektem podobnym do pliku.Kiedy terminal / strumień nadal nie może zakodować wszystkich występujących znaków Unicode i nie chcesz z tego powodu łamać znaków,
print
możesz wprowadzić zachowanie kodowania ze zamianą w tłumaczącym obiekcie podobnym do pliku.Oto przykład:
Używanie zwykłych literałów łańcuchowych poza ascii w kodzie Python 2/2 + 3
Myślę, że jedynym dobrym powodem zmiany globalnego domyślnego kodowania (tylko na UTF-8) jest decyzja dotycząca kodu źródłowego aplikacji - a nie problemy z kodowaniem strumienia I / O: Do zapisywania literałów łańcuchowych poza ascii do kodu bez wymuszania aby zawsze używać
u'string'
ucieczki stylu Unicode. Można to zrobić dość konsekwentnie (pomimo tego, co mówi artykuł anonbadger ), dbając o podstawę kodu źródłowego Python 2 lub Python 2 + 3, który konsekwentnie używa zwykłych literałów ciągów ascii lub UTF-8 - o ile te ciągi potencjalnie podlegają wyciszeniu Konwersja Unicode i przechodzenie między modułami lub potencjalnie przejście do standardowego wyjścia. W tym celu preferuj „# encoding: utf-8
"lub ascii (brak deklaracji). Zmień lub usuń biblioteki, które nadal polegają w bardzo głupi sposób na błędach domyślnego kodowania ascii poza chr # 127 (co jest dziś rzadkością).I zrób to na starcie aplikacji (i / lub przez sitecustomize.py) jako dodatek do
SmartStdout
powyższego schematu - bez użyciareload(sys)
:W ten sposób literały łańcuchowe i większość operacji (z wyjątkiem iteracji znaków) działają wygodnie, bez myślenia o konwersji Unicode, tak jakby istniał tylko Python3. Oczywiście we / wy pliku zawsze trzeba uważać na kodowanie - tak jak w Pythonie3.
Uwaga: łańcuchy
SmartStdout
zwykłe są następnie niejawnie konwertowane z utf-8 do Unicode, zanim zostaną przekonwertowane na kodowanie strumienia wyjściowego.źródło
Oto podejście, którego użyłem do stworzenia kodu, który był kompatybilny zarówno z python2, jak i python3 i zawsze dawał wyjście utf8 . 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 z biblioteki standardowej). Może to spowodować problemy dla twoich bazowych bibliotek, ale w prostym przypadku, gdy masz dobrą kontrolę nad tym, jak sys.stdout out jest używany w twoim frameworku, może to być rozsądne podejście.źródło
To rozwiązało problem.
źródło
To jest szybki hack dla każdego, kto (1) na platformie Windows (2) używa Pythona 2.7 i (3) zirytowany, ponieważ ładne oprogramowanie (tj. Nie napisane przez ciebie, więc nie od razu kandydat do kodowania / dekodowania drukowania manewry) nie będą wyświetlać "ładnych znaków Unicode" w środowisku IDLE (Pythonwin drukuje dobrze unicode). Na przykład zgrabne symbole logiki pierwszego rzędu, których Stephan Boyer używa w wynikach swojego pedagogicznego dowodu w Prover Logic Pierwszego Porządku .
Nie podobał mi się pomysł wymuszenia ponownego załadowania sys i nie mogłem zmusić systemu do współpracy z ustawieniem zmiennych środowiskowych, takich jak PYTHONIOENCODING (wypróbowałem bezpośrednią zmienną środowiskową Windows, a także upuściłem ją w pliku sitecustomize.py w pakietach witryn jako jedną liner = 'utf-8').
Tak więc, jeśli chcesz zhakować swoją drogę do sukcesu, przejdź do katalogu IDLE, zazwyczaj: „C: \ Python27 \ Lib \ idlelib” Zlokalizuj plik IOBinding.py. Utwórz kopię tego pliku i zapisz go w innym miejscu, aby w razie potrzeby móc przywrócić oryginalne zachowanie. Otwórz plik w idlelib za pomocą edytora (np. IDLE). Przejdź do tego obszaru kodu:
Innymi słowy, zakomentuj oryginalną linię kodu następującą po `` try '', która sprawiła, że zmienna kodowania była równa locale.getdefaultlocale (ponieważ da ci to cp1252, którego nie chcesz) i zamiast tego brutalnie wymuś to na `` utf-8 '(dodając wiersz' encoding = 'utf-8 ', jak pokazano).
Uważam, że wpływa to tylko na wyświetlanie IDLE na standardowe wyjście, a nie na kodowanie używane dla nazw plików itp. (Które jest uzyskiwane we wcześniejszym kodowaniu systemu plików). Jeśli masz problem z jakimkolwiek innym kodem uruchomionym później w IDLE, po prostu zastąp plik IOBinding.py oryginalnym niezmodyfikowanym plikiem.
źródło
Możesz zmienić kodowanie całego systemu operacyjnego. W Ubuntu możesz to zrobić za pomocą
źródło