Изменить кодировку Python по умолчанию? - PullRequest
120 голосов
/ 16 февраля 2010

У меня много проблем "не могу кодировать" и "не могу декодировать" с Python , когда я запускаю свои приложения из консоли. Но в Eclipse PyDev IDE кодировка символов по умолчанию установлена ​​на UTF-8 , и я в порядке.

Я искал для установки кодировки по умолчанию, и люди говорят, что Python удаляет функцию sys.setdefaultencoding при запуске, и мы не можем ее использовать.

Так, каково лучшее решение для этого?

Ответы [ 11 ]

141 голосов
/ 13 июля 2013

Вот более простой метод (взлом), который возвращает вам функцию setdefaultencoding(), которая была удалена из sys:

import sys
# sys.setdefaultencoding() does not exist, here!
reload(sys)  # Reload does the trick!
sys.setdefaultencoding('UTF8')

Это небезопасно делать , хотя: это, очевидно, хак, поскольку sys.setdefaultencoding() преднамеренно удаляется из sys при запуске Python.Повторное включение и изменение кодировки по умолчанию может привести к поломке кода, основанного на ASCII, который является значением по умолчанию (этот код может быть сторонним, что обычно делает его невозможным или опасным).

60 голосов
/ 21 ноября 2014

Если вы получаете эту ошибку при попытке перенаправить / перенаправить вывод вашего скрипта

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)

Просто экспортируйте PYTHONIOENCODING в консоль и затем запустите ваш код.

export PYTHONIOENCODING=utf8

50 голосов
/ 25 октября 2011

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) или оба!

17 голосов
/ 16 февраля 2010

Начиная с PyDev 3.4.1, кодировка по умолчанию больше не изменяется.Подробности смотрите в этом билете .

Для более ранних версий решение состоит в том, чтобы убедиться, что PyDev не работает с UTF-8 в качестве кодировки по умолчанию.Под Eclipse запустите настройки диалога («запустите настройки», если я правильно помню);Вы можете выбрать кодировку по умолчанию на общей вкладке.Измените его на US-ASCII, если вы хотите, чтобы эти ошибки были «ранними» (другими словами: в вашей среде PyDev).Также см. оригинальный блог для этого обходного пути .

13 голосов
/ 16 сентября 2016

Что касается python2 (и только python2), некоторые из предыдущих ответов основаны на использовании следующего хака:

import sys
reload(sys)  # Reload is a hack
sys.setdefaultencoding('UTF8')

Не рекомендуется использовать его (отметьте это или это )

В моем случае это имеет побочный эффект: я использую записные книжки 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 и Conda, это ~/anaconda2/lib/python2.7/sitecustomize.py

8 голосов
/ 17 июня 2015

Об этом есть проницательный пост в блоге.

См. 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.

3 голосов
/ 13 апреля 2018

Это исправило проблему для меня.

import os
os.environ["PYTHONIOENCODING"] = "utf-8"
3 голосов
/ 09 февраля 2017

Первое: reload(sys) и установка некоторой случайной кодировки по умолчанию только с учетом необходимости потока выходного терминала является плохой практикой. reload часто меняет вещи в sys, которые были установлены в зависимости от среды - например, потоки sys.stdin / stdout, sys.excepthook и т. д.

Решение проблемы кодирования на stdout

Лучшее из известных мне решений для решения проблемы кодирования print с использованием Unicode-строк и за пределами ascii str (например, из литералов) в sys.stdout: заботиться о sys.stdout ( файлоподобный объект), который способен и, в случае необходимости, терпим к потребностям:

  • Если 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()

Использование простых строковых литералов в коде Python 2/2 + 3

Единственная веская причина изменить глобальную кодировку по умолчанию (только на UTF-8). Я думаю, что это касается решения исходного кода приложения - а не из-за проблем с кодировкой потоков ввода-вывода: Для записи за пределы -ascii строковые литералы в коде без необходимости всегда использовать экранирование юникода u'string'. Это можно сделать довольно последовательно (несмотря на то, что говорится в статье 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 перед преобразованием в выходной поток, заканчивающийся.

2 голосов
/ 25 мая 2017

Вот подход, который я использовал для создания кода, который был совместим с python2 и python3 и всегда производил utf8 выходные данные. Я нашел этот ответ в другом месте, но не могу вспомнить источник.

Этот подход работает, заменяя sys.stdout чем-то, что не совсем похоже на файл (но все еще использует только вещи из стандартной библиотеки). Это может вызвать проблемы для ваших базовых библиотек, но в простом случае, когда вы имеете хороший контроль над тем, как sys.stdout out используется в вашей среде, это может быть разумным подходом.

sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')
1 голос
/ 06 июня 2017

Это быстрый взлом для всех, кто (1) на платформе Windows (2) работает под управлением Python 2.7 и (3) раздражен, потому что хороший кусок программного обеспечения (т. Е. Не написан вами, поэтому не является кандидатом на кодирование) / decode (маневры печати) не будут отображать «красивые символы юникода» в среде IDLE (Pythonwin печатает отлично Unicode), например, аккуратные символы логики первого порядка, которые Стефан Бойер использует в выводе из своего педагогического средства проверки при First Order Logic Prover .

Мне не понравилась идея принудительной перезагрузки системы, и я не мог заставить систему взаимодействовать с установкой переменных среды, таких как 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 на стандартный вывод, а не на кодировку, используемую для имен файлов и т. Д. (Что было получено ранее в файловой системе кодирования). Если у вас есть проблема с любым другим кодом, который вы запускаете в IDLE позже, просто замените файл IOBinding.py на исходный неизмененный файл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...