Jak ustawić sys.kodowanie stdout w Pythonie 3?
Ustawienie domyślnego kodowania wyjściowego w Pythonie 2 jest dobrze znanym idiomem:
sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
To zawija obiekt sys.stdout
do kodera kodującego wyjście w UTF-8.
Jednak ta technika nie działa w Pythonie 3, ponieważ sys.stdout.write()
oczekuje str
, ale wynikiem kodowania jest bytes
, A błąd występuje, gdy codecs
próbuje zapisać zakodowane bajty do oryginalnego sys.stdout
.
Jak to zrobić w Pythonie 3?
7 answers
Od Pythona 3.7 można zmienić kodowanie standardowych strumieni za pomocą reconfigure()
:
sys.stdout.reconfigure(encoding='utf-8')
Możesz również zmodyfikować sposób obsługi błędów kodowania, dodając parametr errors
.
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-09-17 16:47:35
Python 3.1 dodał io.TextIOBase.detach()
, z notatką w dokumentacji dla sys.stdout
:
Standardowe strumienie są domyślnie w trybie tekstowym. Aby zapisać lub odczytać do nich dane binarne, użyj bazowego bufora binarnego. Na przykład, aby zapisać bajty do
stdout
, Użyjsys.stdout.buffer.write(b'abc')
. Za pomocąio.TextIOBase.detach()
strumienie mogą być domyślnie binarne. Funkcja ta ustawiastdin
istdout
na binarne:def make_streams_binary(): sys.stdin = sys.stdin.detach() sys.stdout = sys.stdout.detach()
Dlatego odpowiedni idiom dla Pythona 3.1 i nowszych to:
sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
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-06-20 09:12:55
Znalazłem ten wątek szukając rozwiązania tego samego błędu,
Alternatywnym rozwiązaniem dla tych już sugerowanych jest ustawienie PYTHONIOENCODING
zmiennej środowiskowej przed uruchomieniem Python, do mojego użytku - jest to mniej kłopotu niż Zamiana sys.stdout
po inicjalizacji Pythona:
PYTHONIOENCODING=utf-8:surrogateescape python3 somescript.py
Z tą zaletą, że nie trzeba edytować kodu Pythona.
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-09-23 05:27:10
Inne odpowiedzi wydają się zalecać użycie codecs
, ale open
działa dla mnie:
import sys
sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf8', buffering=1)
print("日本語")
# Also works with other methods of writing to stdout:
sys.stdout.write("日本語\n")
sys.stdout.buffer.write("日本語\n".encode())
To działa nawet wtedy, gdy uruchamiam go z PYTHONIOENCODING="ascii"
.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-04 15:34:58
Eek! Czy to dobrze znany idiom w Pythonie 2? Dla mnie to niebezpieczna pomyłka.Ustawienie domyślnego kodowania wyjściowego w Pythonie 2 jest dobrze znanym idiomem
To z pewnością zepsuje każdy skrypt, który próbuje napisać binarny na stdout (co będzie potrzebne, jeśli jesteś skryptem CGI zwracającym obraz, na przykład). Bajty i znaki to zupełnie inne zwierzęta; nie jest dobrym pomysłem, aby łatać interfejs, który jest określony tak, aby akceptował bajty z takim, który tylko bierze chars.
CGI i HTTP w ogóle jawnie działają z bajtami. Powinieneś wysyłać bajty tylko do sys.stdout. W Pythonie 3 oznacza to użycie sys.stdout.buffer.write
do wysyłania bajtów bezpośrednio. Kodowanie zawartości strony w celu dopasowania jej parametru charset
powinno być obsługiwane na wyższym poziomie w Twojej aplikacji(w przypadkach, gdy zwracasz zawartość tekstową, a nie binarną). Oznacza to również, że print
nie nadaje się już do CGI.
(Aby dodać do zamieszania, cgihandler wsgiref został złamany w py3k do niedawna, co uniemożliwia wdrożenie WSGI do CGI w ten sposób. Z PEP 3333 i Python 3.2 jest to w końcu wykonalne.)
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
2010-12-07 11:23:47
Użycie detach()
powoduje, że interpreter wypisuje ostrzeżenie, gdy próbuje zamknąć stdout tuż przed jego zakończeniem:
Exception ignored in: <_io.TextIOWrapper mode='w' encoding='UTF-8'>
ValueError: underlying buffer has been detached
Zamiast tego, to działało dobrze dla mnie:
default_out = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
(i oczywiście pisanie do default_out
zamiast stdout.)
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-05 18:43:55
Sys.stdout jest w trybie tekstowym w Pythonie 3. Dlatego piszesz do niego bezpośrednio unicode, a idiom dla Pythona 2 nie jest już potrzebny.
Gdzie to by się nie udało w Pythonie 2:
>>> import sys
>>> sys.stdout.write(u"ûnicöde")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xfb' in position 0: ordinal not in range(128)
Jednak działa po prostu dandy w Pythonie 3:
>>> import sys
>>> sys.stdout.write("Ûnicöde")
Ûnicöde7
Teraz, jeśli twój Python nie wie, jakie jest twoje kodowanie stdouts, jest to inny problem, najprawdopodobniej w kompilacji Pythona.
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
2010-12-07 09:44:02