Я бачив кілька сценаріїв py, які використовують це у верхній частині сценарію. У яких випадках його слід використовувати?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Я бачив кілька сценаріїв py, які використовують це у верхній частині сценарію. У яких випадках його слід використовувати?
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Відповіді:
Відповідно до документації: Це дозволяє переходити від ASCII за замовчуванням до інших кодувань, таких як UTF-8, який виконуватиме Python, коли він повинен декодувати буфер рядків для однокодування.
Ця функція доступна лише під час запуску програми 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 людей мають неправильно визначений локальний елемент або оточення, і їх потрібно встановити:
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 використовує місце користувача (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"
€
Люди розробляли програму 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, а потім введе обробник винятків, щоб відгадати кодування та правильно перетворити його в unicode. Друк: Angstrom (Å®) веде ваш бізнес. Після встановлення кодування за замовчуванням до utf-8 код виявить, що байт-стринг можна інтерпретувати як utf-8, і тому він буде маніпулювати даними та повертати це замість цього: Angstrom (Ů) веде ваш бізнес.
Зміна того, що має бути постійним, матиме драматичні наслідки для модулів, від яких ви залежите. Краще просто виправити дані, що надходять та виходять із коду.
Хоча налаштування дефолтного кодування на 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 сумісним дуже просто і не вимагає цього неприємного злому. Наприклад, чому це спричиняє дуже реальні проблеми, дивіться мій досвід, коли Амазонка возиться з цим припущенням: stackoverflow.com/questions/39465220/…
PYTHONIOENCODING="UTF-8"
допоміг моєму середовищу Python2.7 Django-1.11. Дякую.
detect_encoding
.
detect_encoding
це метод, який може виявити кодування рядка на основі мовних підказок.
#!/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
буду працювати
Перша небезпека полягає в 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, або здійснює перекодування за допомогою обробника помилок, що тепер призводить до несподіваного результату. А оскільки весь код протестовано за замовчуванням, ви суворо перебуваєте на "непідтримуваній" території тут , і ніхто не дає вам гарантій того, як буде вести їх код.