Вопрос-Ответ

Why should we NOT use sys.setdefaultencoding("utf-8") in a py script?

Почему мы НЕ ДОЛЖНЫ использовать sys.setdefaultencoding("utf-8") в py-скрипте?

Я видел несколько py-скриптов, которые используют это в верхней части скрипта. В каких случаях это следует использовать?

import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Переведено автоматически
Ответ 1

Согласно документации: Это позволяет вам переключаться с ASCII по умолчанию на другие кодировки, такие как UTF-8, которые среда выполнения Python будет использовать всякий раз, когда ей нужно декодировать строковый буфер в unicode.

Эта функция доступна только во время запуска Python, когда Python сканирует среду. Он должен вызываться в общесистемном модуле, sitecustomize.py После того, как этот модуль был оценен, setdefaultencoding() функция удаляется из sys модуля.

Единственный способ реально использовать его - это перезагрузка, которая возвращает атрибут обратно.

Кроме того, использование sys.setdefaultencoding() всегда не поощрялось, и в py3k это стало запретом. Кодировка py3k жестко привязана к "utf-8", и ее изменение вызывает ошибку.

Я предлагаю несколько советов для чтения:

Ответ 2

tl;dr

Ответ - НИКОГДА! (если вы действительно не знаете, что делаете)

в 9/10 случаях решение может быть найдено при правильном понимании кодирования / декодирования.

У 1/10 человек неправильно определена локаль или среда, и им необходимо установить:

PYTHONIOENCODING="UTF-8"  

в их среде для устранения проблем с консольной печатью.

Что он делает?

sys.setdefaultencoding("utf-8") (зачеркнуто, чтобы избежать повторного использования) изменяет кодировку / декодирование по умолчанию, используемое всякий раз, когда Python 2.x должен преобразовать Unicode() в str() (и наоборот), а кодировка не задана. Т.е.:

str(u"\u20AC")
unicode("€")
"{}".format(u"\u20AC")

В Python 2.x кодировка по умолчанию установлена в ASCII, и приведенные выше примеры завершатся неудачей с:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)

(Моя консоль настроена как UTF-8, поэтому "€" = '\xe2\x82\xac', следовательно, включено исключение \xe2)

или

UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)

sys.setdefaultencoding("utf-8") это позволит им работать для меня, но не обязательно будет работать для людей, которые не используют UTF-8. Значение ASCII по умолчанию гарантирует, что предположения о кодировании не будут учтены в коде

Консоль

sys.setdefaultencoding("utf-8") также имеет побочный эффект появления исправления sys.stdout.encoding, используемого при выводе символов на консоль. Python использует локаль пользователя (Linux / OS X / Un * x) или кодовую страницу (Windows), чтобы установить это. Иногда локаль пользователя нарушается, и требуется просто PYTHONIOENCODING исправить консольную кодировку.

Пример:

$ 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"

Что такого плохого в sys.setdefaultencoding("utf-8")?

Люди разрабатывали на Python 2.x в течение 16 лет, понимая, что кодировкой по умолчанию является ASCII. UnicodeError методы обработки исключений были написаны для преобразования строки в Юникод для строк, которые, как обнаружено, содержат не ASCII.

От 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"))

До установки defaultencoding этот код не смог бы декодировать “Å” в кодировке ascii, а затем вошел бы в обработчик исключений, чтобы угадать кодировку и правильно преобразовать ее в unicode. Печать: Angstrom (Å®) управляет вашим бизнесом. Как только вы установите defaultencoding в utf-8, код обнаружит, что byte_string может интерпретироваться как utf-8, и поэтому он исказит данные и вернет вместо этого следующее: Angstrom (Ů) управляет вашим бизнесом.


Изменение того, что должно быть константой, окажет существенное влияние на модули, от которых вы зависите. Лучше просто исправить данные, поступающие в ваш код и из него.

Пример проблемы

Хотя установка defaultencoding в значение UTF-8 не является основной причиной в следующем примере, это показывает, как маскируются проблемы и как при изменении входной кодировки код неочевидным образом прерывается: UnicodeDecodeError: кодек 'utf8' не может декодировать байт 0x80 в позиции 3131: недопустимый начальный байт

Ответ 3
#!/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)

в командной строке работает, отправки в sdtout нет,
так что это один из обходных путей - записать в стандартный вывод .

Я использовал другой подход, который не запускается, если sys.stdout.encoding не определен, или, другими словами, сначала нужно экспортировать PYTHONIOENCODING= UTF-8 для записи в 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)



итак, используя тот же пример:

export PYTHONIOENCODING=UTF-8
./test.py > output.txt

будет работать

Ответ 4

  • Первая опасность заключается в reload(sys).


    Когда вы перезагружаете модуль, вы фактически получаете две копии модуля в вашей среде выполнения. Старый модуль является объектом Python, как и все остальное, и остается живым до тех пор, пока на него есть ссылки. Таким образом, половина объектов будет указывать на старый модуль, а половина - на новый. Когда вы вносите какие-либо изменения, вы никогда не увидите, что они произойдут, если какой-то случайный объект не увидит изменения:


    (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>

  • Теперь, sys.setdefaultencoding() правильно


    Все , на что это влияет, - это неявное преобразование str<->unicode. Теперь, utf-8 это самая разумная кодировка на планете (обратно совместимая с ASCII и всеми другими), преобразование теперь "просто работает", что может пойти не так?


    Ну, что угодно. И в этом опасность.



    • Может быть какой-то код, который полагается на то, что UnicodeError выдается для ввода, отличного от ASCII, или выполняет перекодирование с помощью обработчика ошибок, который теперь выдает неожиданный результат. И поскольку весь код тестируется с настройками по умолчанию, вы находитесь строго на "неподдерживаемой" территории здесь, и никто не дает вам гарантий относительно того, как будет вести себя их код.

    • Перекодирование может привести к неожиданным или непригодным для использования результатам, если не все в системе использует UTF-8 потому что Python 2 на самом деле имеет несколько независимых "строковых кодировок по умолчанию". (Помните, программа должна работать для заказчика, на оборудовании заказчика.)

      • Опять же, хуже всего то, что вы этого никогда не узнаете, потому что преобразование неявное - вы действительно не знаете, когда и где это происходит. (Python Zen, koan 2, привет!) Вы никогда не узнаете, почему (и работает ли) ваш код в одной системе и ломается в другой. (Или, что еще лучше, работает в IDE и ломается в консоли.)



2023-08-05 21:47 python