Почему мы не должны использовать sys.setdefaultencoding ("utf-8") в скрипте py?
Я видел несколько скриптов py, которые используют это в верхней части скрипта. В каких случаях его следует использовать?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
4 ответов
согласно документации: это позволяет переключаться с ASCII по умолчанию на другие кодировки, такие как UTF-8, которые среда выполнения Python будет использовать всякий раз, когда ей нужно декодировать строковый буфер в unicode.
эта функция доступна только во время запуска Python, когда Python сканирует среду. Он должен быть вызван в общесистемном модуле,sitecustomize.py
, после того, как этот модуль был оценен,setdefaultencoding()
функция удаляется из sys
модуль.
только способ фактически использовать его - это перезагрузить хак,который возвращает атрибут.
и использование sys.setdefaultencoding()
всегда был обескуражен, и это стало no-op в py3k. Кодировка py3k жестко связана с "utf-8", и изменение ее вызывает ошибку.
Я предлагаю несколько советов для чтение:
- http://blog.ianbicking.org/illusive-setdefaultencoding.html
- http://nedbatchelder.com/blog/200401/printing_unicode_from_python.html
- http://www.diveintopython3.net/strings.html#one-ring-to-rule-them-all
- http://boodebr.org/main/python/all-about-python-and-unicode
- http://blog.notdot.net/2010/07/Getting-unicode-right-in-Python
tl; dr
ответ никогда! (если вы действительно не знаете, что делаете)
9/10 раз решение может быть разрешено с надлежащим пониманием кодирования / декодирования.
1/10 человек имеют неправильно определенный язык или среду и должны установить:
PYTHONIOENCODING="UTF-8"
в их среде, чтобы исправить проблемы печати консоли.
что это делать?
(пробит, чтобы избежать повторного использования) изменяет кодировку/декодирование по умолчанию, используемое всякий раз, когда Python 2.x необходимо преобразовать Unicode () в str () (и наоборот), и кодировка не задана. Т. е.:sys.setdefaultencoding("utf-8")
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)
позволит им работать для меня, но не обязательно будет работать для людей, которые не используют UTF-8. по умолчанию ASCII гарантирует, что предположения кодирования не запечены в кодsys.setdefaultencoding("utf-8")
консоль
также имеет побочный эффект появления, чтобы исправить sys.setdefaultencoding("utf-8")
sys.stdout.encoding
, используемых при печати символов на консоли. Python использует пользователя locale (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
методы обработки исключений были записаны в обрабатывать преобразования string в 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"))
до установки defaultencoding этот код не сможет декодировать " Å " в кодировке ascii, а затем введет обработчик исключений, чтобы угадать кодировку и правильно превратить ее в unicode. Печать: Angstrom (Å®) запускает бизнес. Как только вы установите defaultencoding в utf-8, код обнаружит, что byte_string можно интерпретировать как utf-8, и поэтому он будет искажать данные и возвращать это: Angstrom (Ů) запускает ваш бизнес.
изменение того, что должно быть константой, будет иметь драматические последствия для модулей, от которых вы зависите. Лучше всего фиксировать данные в ваш код.
пример проблемы
при установке defaultencoding в UTF-8 не является основной причиной в следующем примере, он показывает, как маскируются проблемы и как при изменении входной кодировки код неочевидно прерывается: UnicodeDecodeError: кодек "utf8" не может декодировать байт 0x80 в позиции 3131: недопустимый начальный байт
#!/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)
на shell работает, отправка в sdtout не , так что это один обходной путь, чтобы написать stdout .
Я сделал другой подход, который не запускается, если sys.стандартный вывод.кодирование не определяет, или другими словами, нужно экспортировать 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
совместимость
-
первая опасность заключается в
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, Коан 2 ahoy!) Вы никогда не узнаете, почему (и если) ваш код работает в одной системе и ломается в другой. (Или еще лучше, работает в IDE и врывается приставка.)
- там может быть некоторый код, который полагается на