Почему мы не должны использовать sys.setdefaultencoding( "utf-8" ) в py script?
Я видел несколько скриптов py, которые используют это в верхней части script. В каких случаях его следует использовать?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Ответы
Ответ 1
В соответствии с документацией: Это позволяет вам переключиться с ASCII по умолчанию на другие кодировки, такие как UTF-8, которые будут использоваться во время исполнения Python, когда потребуется декодировать буфер строки в unicode.
Эта функция доступна только при запуске Python, когда Python сканирует среду. Он должен вызываться в общесистемном модуле, sitecustomize.py
. После того, как этот модуль был оценен, функция setdefaultencoding()
удаляется из модуля sys
.
Единственный способ использовать его - это перезагрузить хак, который возвращает атрибут.
Кроме того, использование sys.setdefaultencoding()
всегда было обескуражено, и оно стало no-op в py3k. Кодировка py3k жестко связана с "utf-8", а изменение вызывает ошибку.
Я предлагаю несколько указателей для чтения:
Ответ 2
ТЛ; др
Ответ НИКОГДА ! (если вы действительно не знаете, что делаете)
Решение в 9/10 раз может быть разрешено при правильном понимании кодирования/декодирования.
1/10 человек имеют неверно определенный язык или среду и должны установить:
PYTHONIOENCODING="UTF-8"
в их среде для устранения проблем с консольной печатью.
Что оно делает?
sys.setdefaultencoding("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
обработки исключений 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"))
Ранее для установки defaultencoding этот код не смог бы декодировать "Å" в кодировке ascii, а затем должен был бы ввести обработчик исключения, чтобы угадать кодировку и правильно превратить ее в юникод. Печать: Angstrom (Å®) управляет вашим бизнесом. После того, как вы установили значение по умолчанию для utf-8, код найдет, что byte_string может быть интерпретирован как utf-8, и поэтому он будет искажать данные и вместо этого возвращает это: Angstrom (Ů) запускает вашу компанию.
Изменение того, что должно быть постоянным, будет иметь драматические последствия для модулей, от которых вы зависите. Лучше всего исправить данные, входящие и выходящие из вашего кода.
Пример проблемы
Хотя установка стандартного кодирования для UTF-8 не является основной причиной в следующем примере, это показывает, как проблемы маскируются и как при изменении входной кодировки код прерывается неочевидным образом: UnicodeDecodeError: кодек "utf8" может 't декодировать байт 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)
на shell работает, отправка в 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 ahoy!) Вы никогда не узнаете, почему (и если) ваш код работает на одной системе и разрывается на другой. (Или еще лучше, работает в среде IDE и перерывы в консоли.)
Ответ 5
может быть, это другой способ:
[email protected]:/usr/local/apache2/bin# LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php
это работает для меня !!
Ответ 6
вы можете использовать модуль кодеков в python3. например
import codecs
fopen = codecs.open('file_name.txt', 'r', 'UTF-8')