Почему мы НЕ должны использовать sys.setdefaultencoding ("utf-8") в скрипте py? - PullRequest
153 голосов
/ 30 сентября 2010

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

import sys
reload(sys)
sys.setdefaultencoding("utf-8")

Ответы [ 4 ]

134 голосов
/ 30 сентября 2010

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

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

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

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

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

53 голосов
/ 20 декабря 2015

ТЛ; др

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

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") позволит им работать на me , но не обязательно будет работать для людей, которые не используют 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 Методы обработки исключений были написаны для обработки преобразований строки в Unicode для строк, которые, как обнаружено, содержат не-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"))

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

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

Пример задачи

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

18 голосов
/ 19 июля 2011
#!/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

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

3 голосов
/ 22 апреля 2018
  • Первая опасность заключается в 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 и ломается в консоли.)
...