Изменение кодировки по умолчанию для Python?
У меня есть много проблем "не могу кодировать" и "не могу декодировать" с Python, когда я запускаю свои приложения из консоль. Но в Eclipse PyDev IDE, по умолчанию кодировка символов установлена на UTF-8, и я в порядке.
Я искал для настройки кодировки по умолчанию, и люди говорят, что Python удаляет функцию sys.setdefaultencoding
при запуске, и мы не можем ее использовать.
Так какое лучшее решение для этого?
Ответы
Ответ 1
Вот более простой метод (hack), который возвращает функцию setdefaultencoding()
, которая была удалена из sys
:
import sys
# sys.setdefaultencoding() does not exist, here!
reload(sys) # Reload does the trick!
sys.setdefaultencoding('UTF8')
Это не безопасно делать: это, очевидно, взлом, поскольку sys.setdefaultencoding()
намеренно удаляется из sys
при запуске Python. Повторное включение и изменение кодировки по умолчанию может привести к поломке кода, который полагается на ASCII по умолчанию (этот код может быть сторонним, что обычно фиксирует это невозможно или опасно).
Ответ 2
A) Для управления выводом sys.getdefaultencoding()
:
python -c 'import sys; print(sys.getdefaultencoding())'
ascii
Тогда
echo "import sys; sys.setdefaultencoding('utf-16-be')" > sitecustomize.py
и
PYTHONPATH=".:$PYTHONPATH" python -c 'import sys; print(sys.getdefaultencoding())'
utf-16-be
Вы можете добавить файл sitecustomize.py в PYTHONPATH
..
Также вы можете попробовать reload(sys).setdefaultencoding
с помощью @EOL
B) Для управления stdin.encoding
и stdout.encoding
вы хотите установить PYTHONIOENCODING
:
python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'
ascii ascii
Тогда
PYTHONIOENCODING="utf-16-be" python -c 'import sys;
print(sys.stdin.encoding, sys.stdout.encoding)'
utf-16-be utf-16-be
Наконец: вы можете использовать A) или B) или оба!
Ответ 3
Если вы получаете эту ошибку, когда пытаетесь передать/перенаправить вывод своего script
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
Просто экспортируйте PYTHONIOENCODING в консоли, а затем запустите свой код.
export PYTHONIOENCODING=utf8
Ответ 4
Начиная с PyDev 3.4.1, кодировка по умолчанию больше не изменяется.
Подробнее см. этот билет.
Для более ранних версий решение состоит в том, чтобы убедиться, что PyDev не работает с UTF-8 в качестве кодировки по умолчанию. В Eclipse запустите диалоговые настройки ( "запустите конфигурацию", если я правильно помню); вы можете выбрать кодировку по умолчанию на общей вкладке. Измените его на US-ASCII, если вы хотите, чтобы эти ошибки были ранними (другими словами: в среде PyDev). Также см. оригинальное сообщение в блоге для этого обходного пути.
Ответ 5
Есть проницательное сообщение в блоге об этом.
См. https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/.
Я перефразирую его содержимое ниже.
В python 2, который был не так строго типизирован относительно кодирования строк, вы могли выполнять операции с по-разному закодированными строками и преуспеть. Например. следующее возвращает True
.
u'Toshio' == 'Toshio'
Это будет сохраняться для каждой (нормальной, нефиксированной) строки, которая была закодирована в sys.getdefaultencoding()
, которая по умолчанию была ascii
, но не других.
Кодировка по умолчанию должна была быть изменена в общесистемной области в site.py
, но не в другом месте. Хаки (также представленные здесь), чтобы установить его в пользовательских модулях, были именно такими: хаками, а не решением.
Python 3 изменил системную кодировку на значение по умолчанию на utf-8 (когда LC_CTYPE является unicode-aware), но основная проблема была решена с требованием явно кодировать строки "байтов" всякий раз, когда они используются с строками unicode.
Ответ 6
Что касается python2 (и только python2), некоторые из предыдущих ответов полагаются на использование следующего взлома:
import sys
reload(sys) # Reload is a hack
sys.setdefaultencoding('UTF8')
Не рекомендуется использовать его (отметьте this или this)
В моем случае он имеет побочный эффект: я использую ipython-ноутбуки, и как только я запустил код, функция "print" больше не работает. Я предполагаю, что это будет решение, но все же я считаю, что использование хака не должно быть правильным вариантом.
После того, как вы попробовали много вариантов, тот, который работал у меня, был , используя тот же код в sitecustomize.py
, где этот фрагмент кода должен быть. После оценки этого модуля функция setdefaultencoding удаляется из sys.
Итак, решение состоит в том, чтобы добавить в файл /usr/lib/python2.7/sitecustomize.py
код:
import sys
sys.setdefaultencoding('UTF8')
Когда я использую virtualenvwrapper, файл, который я редактирую, ~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py
.
И когда я использую python notebooks и conda, это ~/anaconda2/lib/python2.7/sitecustomize.py
Ответ 7
Вы хотите написать испанские слова (para escribir la ñ en python)
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
print "Piña"
Ответ 8
Во-первых: reload(sys)
и установка какой-либо случайной кодировки по умолчанию только в отношении потребности в выходном терминальном потоке - это плохая практика. reload
часто меняет объекты в sys, которые были установлены в зависимости от среды - например, sys.stdin/stdout, sys.excepthook и т.д.
Решение проблемы с кодировкой на stdout
Лучшее решение, которое я знаю для решения проблемы с кодировкой print
'строк unicode и за пределами ascii str
(например, из литералов) на sys.stdout, - это: позаботиться о sys.stdout(file- подобный объект), который способен и, возможно, терпимо относиться к потребностям:
-
Когда sys.stdout.encoding
по какой-то причине None
или несуществующий, или ошибочно ложный или "меньше", чем то, на что способен терминал или поток stdout, затем попробуйте указать правильный .encoding
. Наконец, заменив sys.stdout & sys.stderr
на переводный файл-подобный объект.
-
Когда терминал/поток все еще не могут кодировать все возникающие символы юникода, и когда вы не хотите разорвать print
только из-за этого, вы можете ввести поведение кодирования с заменой в файл перевода -подобный объект.
Вот пример:
#!/usr/bin/env python
# encoding: utf-8
import sys
class SmartStdout:
def __init__(self, encoding=None, org_stdout=None):
if org_stdout is None:
org_stdout = getattr(sys.stdout, 'org_stdout', sys.stdout)
self.org_stdout = org_stdout
self.encoding = encoding or \
getattr(org_stdout, 'encoding', None) or 'utf-8'
def write(self, s):
self.org_stdout.write(s.encode(self.encoding, 'backslashreplace'))
def __getattr__(self, name):
return getattr(self.org_stdout, name)
if __name__ == '__main__':
if sys.stdout.isatty():
sys.stdout = sys.stderr = SmartStdout()
us = u'aouäöüфżß²'
print us
sys.stdout.flush()
Использование строковых литералов за пределами ascii в коде Python 2/2 + 3
Единственная веская причина изменить глобальную кодировку по умолчанию (только для UTF-8), я думаю, это решение приложения исходный код - и не из-за проблем с кодированием потока ввода-вывода: для записи string-ascii-string литералы в код, не будучи вынужденным всегда использовать u'string'
стирание unicode стиля. Это можно сделать довольно последовательно (несмотря на то, что говорит статья anonbadger), заботясь о исходной кодовой базе Python 2 или Python 2 + 3, которая последовательно использует простые строковые литералы ascii или UTF-8 - насколько эти строки потенциально подвергаются молчащему преобразованию в Юникоде и перемещаться между модулями или, возможно, перейти на стандартный вывод. Для этого предпочитайте "# encoding: utf-8
" или ascii (без объявления). Измените или отбросьте библиотеки, которые по-прежнему полагаются очень глупым образом на ascii-ошибки кодирования по умолчанию за пределами chr # 127 (что редко встречается сегодня).
И сделайте это при запуске приложения (и/или через sitecustomize.py) в дополнение к схеме SmartStdout
выше - без использования reload(sys)
:
...
def set_defaultencoding_globally(encoding='utf-8'):
assert sys.getdefaultencoding() in ('ascii', 'mbcs', encoding)
import imp
_sys_org = imp.load_dynamic('_sys_org', 'sys')
_sys_org.setdefaultencoding(encoding)
if __name__ == '__main__':
sys.stdout = sys.stderr = SmartStdout()
set_defaultencoding_globally('utf-8')
s = 'aouäöüфżß²'
print s
Таким образом, строковые литералы и большинство операций (кроме итерации символов) работают комфортно, не думая о преобразовании в Юникоде, как будто бы только Python3.
Файловый ввод/вывод, конечно, всегда требует особой осторожности в отношении кодировок - как и в Python3.
Примечание. Строки равнины затем неявно преобразуются из utf-8 в unicode в SmartStdout
перед преобразованием в обратный поток.
Ответ 9
Вот такой подход, который я использовал для создания кода, который был совместим как с python2, так и с python3 и всегда производил вывод utf8. Я нашел этот ответ в другом месте, но я не могу вспомнить источник.
Этот подход работает, заменив sys.stdout
тем, что не является файловым (но все еще используется только в стандартной библиотеке). Это может вызвать проблемы для ваших базовых библиотек, но в простом случае, когда у вас есть хороший контроль над тем, как sys.stdout используется через ваши рамки, это может быть разумным подходом.
sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')
Ответ 10
Это быстрый взлом для всех, кто (1) на платформе Windows (2) работает Python 2.7 и (3) раздражен, потому что хороший кусок программного обеспечения (т.е. не написанный вами так не сразу кандидат для кодирования/декодирование печати) не будет отображать "симпатичные символы Юникода" в среде IDLE (Pythonwin печатает юникод в порядке), например, аккуратные символы логики первого порядка, которые использует Стефан Бойер на выходе из своей педагогической программы на Логический прогон первого порядка.
Мне не нравилась идея принудительного перезагрузки sys, и я не мог заставить систему сотрудничать с настройкой переменных окружения, таких как PYTHONIOENCODING (попробовал прямую переменную среды Windows, а также сбросил ее в файле sitecustomize.py в пакетах сайта как один вкладыш = 'utf-8').
Итак, если вы готовы взломать свой путь к успеху, перейдите в свой каталог IDLE, как правило:
"C:\python27\Lib\idlelib"
Найдите файл IOBinding.py. Сделайте копию этого файла и сохраните его в другом месте, чтобы вы могли вернуться к исходному поведению, когда вы выберете. Откройте файл в idlelib с помощью редактора (например, IDLE). Перейдите в эту область кода:
# Encoding for file names
filesystemencoding = sys.getfilesystemencoding()
encoding = "ascii"
if sys.platform == 'win32':
# On Windows, we could use "mbcs". However, to give the user
# a portable encoding name, we need to find the code page
try:
# --> 6/5/17 hack to force IDLE to display utf-8 rather than cp1252
# --> encoding = locale.getdefaultlocale()[1]
encoding = 'utf-8'
codecs.lookup(encoding)
except LookupError:
pass
Другими словами, закомментируйте исходную строку кода после "try", которая делала переменную кодировки равной locale.getdefaultlocale(потому что это даст вам cp1252, который вам не нужен), а вместо этого перетащите ее в ' utf-8 '(добавив строку' encoding = 'utf-8', как показано).
Я считаю, что это влияет только на отображение IDLE на stdout, а не на кодировку, используемую для имен файлов и т.д. (что получено ранее в файловой системе). Если у вас возникла проблема с любым другим кодом, который вы запускаете в IDLE позже, просто замените файл IOBinding.py исходным немодифицированным файлом.