Как это не является точной копией опасностей sys.setdefaultencoding ('utf-8') ? Хотя этот (2010) запрос предшествует этому (2015)? Но на этот вопрос тоже есть хорошие ответы. Что делать? Кроме того, чтобы быть ясным, этот вопрос имеет смысл только на Python 2, а не 3, но это нигде не отмечено и не упоминается.
Согласно документации: Это позволяет вам переключаться с ASCII по умолчанию на другие кодировки, такие как UTF-8, которые среда исполнения Python будет использовать всякий раз, когда ему нужно будет декодировать строковый буфер в Unicode.
Эта функция доступна только во время запуска Python, когда Python сканирует среду. Он должен вызываться в общесистемном модуле. sitecustomize.pyПосле оценки этого модуля setdefaultencoding()функция удаляется из sysмодуля.
Единственный способ на самом деле использовать это с помощью хака перезагрузки, который возвращает атрибут.
Кроме того, использование sys.setdefaultencoding()всегда не поощрялось , и это стало запретом в py3k. Кодировка py3k жестко привязана к «utf-8», и ее изменение вызывает ошибку.
Я хотел бы добавить, что кодировка по умолчанию также используется для кодирования (при записи, sys.stdoutкогда она имеет Noneкодировку, например, при перенаправлении вывода программы Python).
Эрик О Лебиго
14
+1 за "использование sys.setdefaultencoding()всегда не поощрялось"
JFS
7
'hard-wired to 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(или, возможно, что-то еще)
Тино
7
@Tino, кодировка консоли отличается от кодировки по умолчанию.
Аластер МакКормак
59
ТЛ; др
Ответ НИКОГДА ! (если вы действительно не знаете, что делаете)
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.
def welcome_message(byte_string):try:return u"%s runs your business"% byte_string
exceptUnicodeError: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 (Ů) управляет вашим бизнесом.
Изменение того, что должно быть константой, будет иметь драматические последствия для модулей, от которых вы зависите. Лучше просто исправить данные, входящие и исходящие из вашего кода.
В то время как есть сюрпризы sys.setdefaultencoding("utf-8"), хорошо, чтобы код вел себя больше как Python 3. Сейчас 2017 год. Даже когда вы написали ответ в 2015 году, я думаю, что было бы лучше смотреть вперед, а не назад. На самом деле это было самое простое решение для меня, когда я обнаружил, что мой код ведет себя по-разному в Python 2 в зависимости от того, перенаправлен ли вывод (очень неприятная проблема для Python 2). Излишне говорить, что у меня уже есть # coding: utf-8, и мне не нужны обходные пути для Python 3 (на самом деле я должен маскировать setdefaultencodingпроверку использования версии).
Юнвэй Ву
Это замечательно и работает для вас, но sys.setdefaultencoding("utf-8")не делает ваш код Py 2.x совместимым с Python 3. Также он не исправляет внешние модули, которые предполагают, что кодировкой по умолчанию является ASCII. Сделать ваш код совместимым с Python 3 очень просто и не требует этого неприятного хака. Например, почему это вызывает очень реальные проблемы, см. Мой опыт с Amazon, который искажает это предположение: stackoverflow.com/questions/39465220/…
Alastair McCormack
1
@AlastairMcCormack you rock, Мой сайт существует уже несколько месяцев и не может понять, что делать. Наконец, PYTHONIOENCODING="UTF-8"помогла моя среда Python2.7 Django-1.11. Спасибо.
сэм
Я знаю, что вы скопировали пример, но я могу найти пакет detect_encoding.
Дламблин
@dlamblin Пример кода - подтверждение цитаты, и он не должен использоваться в вашем коде. Представьте, что detect_encodingэто метод, который может определять кодирование строки на основе языковых подсказок.
Аластер МакКормак
18
#!/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 isNone):print>> sys.stderr,"please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
exit(1)
Это не отвечает на вопрос, как спросили. Скорее некоторые тангенциальные мысли по этому вопросу.
ivan_pozdeev
3
Первая опасность заключается в reload(sys).
Когда вы перезагружаете модуль, вы фактически получаете две копии модуля во время выполнения. Старый модуль - это объект Python, как и все остальное, и он остается живым, пока есть ссылки на него. Таким образом, половина объектов будет указывать на старый модуль, а половина на новый. Когда вы вносите какое-либо изменение, вы никогда не увидите его появления, когда какой-то случайный объект не увидит изменения:
(ThisisIPython 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]:importIPython.terminal
In[14]:IPython.terminal.interactiveshell.sys.stdout
Out[14]:<colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
Может быть какой-то код, который полагается на то UnicodeError, что его генерируют для ввода не-ASCII, или выполняет транскодирование с помощью обработчика ошибок, который теперь дает неожиданный результат. И поскольку весь код протестирован с настройками по умолчанию, вы находитесь здесь на «неподдерживаемой» территории , и никто не дает вам гарантий того, как будет работать их код.
Опять же, хуже всего то, что вы никогда не узнаете об этом, потому что преобразование неявно - вы не знаете, когда и где оно происходит. (Python Zen, koan 2, ахой!) Вы никогда не узнаете, почему (и если) ваш код работает в одной системе и ломается в другой. (Или еще лучше, работает в IDE и ломается в консоли.)
Ответы:
Согласно документации: Это позволяет вам переключаться с ASCII по умолчанию на другие кодировки, такие как UTF-8, которые среда исполнения Python будет использовать всякий раз, когда ему нужно будет декодировать строковый буфер в Unicode.
Эта функция доступна только во время запуска Python, когда Python сканирует среду. Он должен вызываться в общесистемном модуле.
sitecustomize.py
После оценки этого модуляsetdefaultencoding()
функция удаляется изsys
модуля.Единственный способ на самом деле использовать это с помощью хака перезагрузки, который возвращает атрибут.
Кроме того, использование
sys.setdefaultencoding()
всегда не поощрялось , и это стало запретом в py3k. Кодировка py3k жестко привязана к «utf-8», и ее изменение вызывает ошибку.Я предлагаю несколько указателей для чтения:
источник
sys.stdout
когда она имеетNone
кодировку, например, при перенаправлении вывода программы Python).sys.setdefaultencoding()
всегда не поощрялось"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
(или, возможно, что-то еще)ТЛ; др
Ответ НИКОГДА ! (если вы действительно не знаете, что делаете)
9/10 раз решение может быть решено с правильным пониманием кодирования / декодирования.
1/10 человек имеют неправильно определенную локаль или среду и должны установить:
в их среде, чтобы исправить проблемы печати консоли.
Что оно делает?
(вычеркнуто, чтобы избежать повторного использования) изменяет кодировку / декодирование по умолчанию, используемое всякий раз, когда Python 2.x должен преобразовать Unicode () в str () (и наоборот), а кодировка не указана. То есть:sys.setdefaultencoding("utf-8")
В Python 2.x кодировка по умолчанию установлена в ASCII, и приведенные выше примеры не будут работать с:
(Моя консоль настроена как UTF-8, поэтому
"€" = '\xe2\x82\xac'
исключение включено\xe2
)или
позволит мне это сработать , но не обязательно будет работать для людей, которые не используют UTF-8. По умолчанию ASCII гарантирует, что предположения о кодировке не будут включены в кодsys.setdefaultencoding("utf-8")
Приставка
также имеет побочный эффект появления исправленияsys.setdefaultencoding("utf-8")
sys.stdout.encoding
, используемый при печати символов на консоли. Python использует языковой стандарт пользователя (Linux / OS X / Un * x) или кодовую страницу (Windows), чтобы установить это. Иногда язык пользователя нарушается, и ему просто необходимоPYTHONIOENCODING
исправить кодировку консоли .Пример:
Что такого плохого в
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/
Изменение того, что должно быть константой, будет иметь драматические последствия для модулей, от которых вы зависите. Лучше просто исправить данные, входящие и исходящие из вашего кода.
Пример задачи
Хотя установка defaultencoding в UTF-8 не является основной причиной в следующем примере, она показывает, как проблемы маскируются и как, когда изменяется входная кодировка, код ломается неочевидным образом: UnicodeDecodeError: кодек utf8 может не декодировать байт 0x80 в позиции 3131: неверный начальный байт
источник
sys.setdefaultencoding("utf-8")
, хорошо, чтобы код вел себя больше как Python 3. Сейчас 2017 год. Даже когда вы написали ответ в 2015 году, я думаю, что было бы лучше смотреть вперед, а не назад. На самом деле это было самое простое решение для меня, когда я обнаружил, что мой код ведет себя по-разному в Python 2 в зависимости от того, перенаправлен ли вывод (очень неприятная проблема для Python 2). Излишне говорить, что у меня уже есть# coding: utf-8
, и мне не нужны обходные пути для Python 3 (на самом деле я должен маскироватьsetdefaultencoding
проверку использования версии).sys.setdefaultencoding("utf-8")
не делает ваш код Py 2.x совместимым с Python 3. Также он не исправляет внешние модули, которые предполагают, что кодировкой по умолчанию является ASCII. Сделать ваш код совместимым с Python 3 очень просто и не требует этого неприятного хака. Например, почему это вызывает очень реальные проблемы, см. Мой опыт с Amazon, который искажает это предположение: stackoverflow.com/questions/39465220/…PYTHONIOENCODING="UTF-8"
помогла моя среда Python2.7 Django-1.11. Спасибо.detect_encoding
.detect_encoding
это метод, который может определять кодирование строки на основе языковых подсказок.на оболочке работает, отправка на sdtout нет, так что это один из обходных путей, чтобы написать на stdout.
Я сделал другой подход, который не запускается, если sys.stdout.encoding не определен, или, другими словами, сначала нужно экспортировать PYTHONIOENCODING = UTF-8, чтобы записать в stdout.
Итак, используя тот же пример:
буду работать
источник
Первая опасность заключается в
reload(sys)
.Когда вы перезагружаете модуль, вы фактически получаете две копии модуля во время выполнения. Старый модуль - это объект Python, как и все остальное, и он остается живым, пока есть ссылки на него. Таким образом, половина объектов будет указывать на старый модуль, а половина на новый. Когда вы вносите какое-либо изменение, вы никогда не увидите его появления, когда какой-то случайный объект не увидит изменения:
Теперь
sys.setdefaultencoding()
правильноВсе, на что это влияет - это неявное преобразование
str<->unicode
. Теперь,utf-8
является ли Sanest кодирование на планете (обратно совместимым с ASCII и всеми), преобразование теперь «просто работает», что может пойти не так?Ну ничего. И это опасность.
UnicodeError
, что его генерируют для ввода не-ASCII, или выполняет транскодирование с помощью обработчика ошибок, который теперь дает неожиданный результат. И поскольку весь код протестирован с настройками по умолчанию, вы находитесь здесь на «неподдерживаемой» территории , и никто не дает вам гарантий того, как будет работать их код.источник