Почему мы НЕ должны использовать sys.setdefaultencoding («utf-8») в скрипте py?

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

import sys
reload(sys)
sys.setdefaultencoding("utf-8")
 idbrii19 дек. 2015 г., 16:41
 Alastair McCormack29 нояб. 2015 г., 00:28
@ seanv507, почитай ответы - использовать его серьезно не рекомендуется
 smci15 нояб. 2017 г., 23:02
Как это не точный дубликатОпасности sys.setdefaultencoding ('utf-8')? Хотя этот (2010) запрос предшествует этому (2015)? Но на этот вопрос тоже есть хорошие ответы. Что делать? Кроме того, чтобы быть ясным, этот вопрос имеет смысл только на Python 2, а не 3, но это нигде не отмечено и не упоминается.
 seanv50717 июн. 2015 г., 12:11
есть проблема с использованием этого в ipython,% времени перестает работатьgithub.com/ipython/ipython/issues/8071

Ответы на вопрос(4)

ТЛ; др

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

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

 sam17 нояб. 2017 г., 19:56
@AlastairMcCormack you rock, Мой сайт существует уже несколько месяцев и не может понять, что делать. В заключение,PYTHONIOENCODING="UTF-8" помогло мое окружение Python2.7 Django-1.11. Благодарю.
 dlamblin20 мар. 2018 г., 07:48
Я знаю, что вы скопировали пример, но я могу найти пакетdetect_encoding.
 Alastair McCormack20 мар. 2018 г., 11:56
@dlamblin Пример кода - подтверждение цитаты, и он не должен использоваться в вашем коде. Представь этоdetect_encoding это метод, который может обнаружить кодирование строки на основе языковых подсказок.
 Yongwei Wu18 июл. 2017 г., 11:26
Пока есть сюрпризы вsys.setdefaultencoding("utf-8")хорошо, чтобы код вел себя как Python 3. Сейчас 2017 год. Даже когда вы написали ответ в 2015 году, я думаю, что было бы лучше смотреть вперед, а не назад. На самом деле это было самое простое решение для меня, когда я обнаружил, что мой код ведет себя по-разному в Python 2 в зависимости от того, перенаправлен ли вывод (очень неприятная проблема для Python 2). Излишне говорить, что у меня уже есть# coding: utf-8и мне не нужны обходные пути для Python 3 (на самом деле я должен замаскироватьsetdefaultencoding используя проверку версии).
 Alastair McCormack18 июл. 2017 г., 11:34
Это здорово, и это работает для вас, ноsys.setdefaultencoding("utf-8") не делает ваш код Py 2.x совместимым с Python 3. Он также не исправляет внешние модули, которые предполагают, что кодировкой по умолчанию является ASCII. Создание вашего кода, совместимого с Python 3, очень просто и не требует этого неприятного взлома. Например, почему это вызывает очень реальные проблемы, посмотрите мой опыт с Amazon, который возился с этим предположением:stackoverflow.com/questions/39465220/...
#!/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 нет, так что это один из обходных путей, чтобы написать в stdout.

Я сделал другой подход, который не запускается, если 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

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

 ivan_pozdeev10 авг. 2018 г., 12:43
Это не отвечает на вопрос, как спросили. Скорее некоторые тангенциальные мысли по этому вопросу.
 Sérgio11 авг. 2018 г., 02:11
так ? люди голосуют, когда это решает проблему ...
Решение Вопроса

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

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

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

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

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

http://blog.ianbicking.org/illusive-setdefaultencoding.htmlhttp://nedbatchelder.com/blog/200401/printing_unicode_from_python.htmlhttp://www.diveintopython3.net/strings.html#one-ring-to-rule-them-allhttp://boodebr.org/main/python/all-about-python-and-unicodehttp://blog.notdot.net/2010/07/Getting-unicode-right-in-Python
 alvas26 дек. 2014 г., 19:59
 Tino28 сент. 2015 г., 01:01
«жестко привязанный к utf-8» не соответствует действительности, он не является аппаратным и не всегдаUTF-8. LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)' даетUTF-8 ноLC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)' даетANSI_X3.4-1968 (или возможно что-то еще)
 Eric O Lebigot13 июл. 2013 г., 10:15
Я хотел бы добавить, что кодировка по умолчанию также используется длякодирование (при написанииsys.stdout когда у него естьNone кодирование, как при перенаправлении вывода программы Python).
 jfs12 апр. 2014 г., 18:17
+1 за"использованиеsys.setdefaultencoding() всегда был обескуражен
 Alastair McCormack20 дек. 2015 г., 10:28
@Tino, кодировка консоли отличается от кодировки по умолчанию.
 Alastair McCormack25 дек. 2015 г., 12:37
@ Тино, это сложная и плохо документированная часть языка. Чем больше об этом написано, тем лучше :)
 ivan_pozdeev22 апр. 2018 г., 00:13
Это на самом деле не отвечает на вопрос. «Обескураженный» не является аргументом.
 mbb20 нояб. 2012 г., 23:19
Отличный материал, хотя здесь слишком много смерти от слишком большого количества информации. Я узнал больше всего, сосредоточившись на этой статье:blog.notdot.net/2010/07/Getting-unicode-right-in-Python
 Tino25 дек. 2015 г., 12:33
@AlastairMcCormack Спасибо, что поправили меня, это заставило меня осознать, чтоstdin/stdout/stderr сейчас (это было совершенно иначе раньше) не зависит отsys.getdefaultencoding() а такжеsetdefaultencoding только принимает«UTF-8». Поэтому, пожалуйста, проигнорируйте мое первое предложение, но остальная часть моего комментария все же может помочь другим не попасть в ту же ловушку.

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

Ваш ответ на вопрос