Изменить кодировку Python по умолчанию?

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

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

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

15 ответов

Решение

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

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

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

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

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

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

export PYTHONIOENCODING=utf8

А) Для контроля 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

Б) контролировать 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) или оба!

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

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

Что касается 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

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

См. 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), но фундаментальная проблема была решена с требованием явно кодировать "байтовые" строки всякий раз, когда они используются со строками Unicode.

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

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

sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')

Первый: 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()

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

Я думаю, что единственная веская причина изменить глобальную кодировку по умолчанию (только на UTF-8) касается решения об исходном коде приложения, а не из-за проблем с кодировкой потока ввода-вывода: для записи строковых литералов за пределами ascii в код без принудительного применения всегда использовать u'string' Стиль Unicode Escape. Это может быть сделано довольно последовательно (несмотря на то, что говорится в статье anonbadger), позаботившись о основе исходного кода Python 2 или Python 2 + 3, которая последовательно использует литералы простых строк ascii или UTF-8 - насколько эти строки потенциально подвергаются молчанию Unicode преобразование и перемещение между модулями или, возможно, перейти на стандартный вывод. За что предпочитаю # 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 до преобразования в конечный поток вывода.

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

Мне не нравилась идея принудительной перезагрузки системы, и я не мог заставить систему взаимодействовать с установкой переменных среды, таких как 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 на исходный неизмененный файл.

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

import os
os.environ["PYTHONIOENCODING"] = "utf-8"

Windows устанавливает переменную среды PYTHONUTF8=1

Вы можете изменить кодировку всей вашей операционной системы. В Ubuntu это можно сделать с помощью

sudo apt install locales 
sudo locale-gen en_US en_US.UTF-8    
sudo dpkg-reconfigure locales

Если вам нужна только стабильная UTF-8поддержка в файле read/ writeбез одинаковых объявлений везде, вот два решения:

1. Патч ioмодуль во время выполнения (опасная операция на свой страх и риск)

      import pathlib as pathlib
import tempfile

import chardet


def patchIOWithUtf8Default():
    import builtins
    import importlib.util
    import sys
    spec = importlib.util.find_spec("io")
    module = importlib.util.module_from_spec(spec)
    exec(compile(spec.loader.get_source(spec.name) + """
    def open(*args, **kwargs):
        args = list(args)
        mode = kwargs.get('mode', (args + [''])[1])
        if (len(args) < 4 and 'b' not in mode) or 'encoding' in kwargs:
            kwargs['encoding'] = 'utf8'
        elif len(args) >= 4 and args[3] is None:
            args[3] = 'utf8'
        return _io.open(*args, **kwargs)
    """, module.__spec__.origin, "exec"), module.__dict__)
    sys.modules[module.__name__] = module
    builtins.open = __import__("io").open
    importlib.reload(importlib.import_module("pathlib"))


def main():
    patchIOWithUtf8Default()
    filename = tempfile.mktemp()
    text = "Common\n常\nSense\n识\n天地玄黄"
    print("Original text:", repr(text))
    pathlib.Path(filename).write_text(text)
    encoding = chardet.detect(open(filename, mode="rb").read())["encoding"]
    print("Written encoding by pathlib:", encoding)
    print("Written text by pathlib:", repr(open(filename, newline="", encoding=encoding).read()))


if __name__ == '__main__':
    main()

Пример вывода:

      Original text: 'Common\n常\nSense\n识\n天地玄黄'
Written encoding by pathlib: utf-8
Written text by pathlib: 'Common\r\n常\r\nSense\r\n识\r\n天地玄黄'

2. Используйте третью библиотеку в качестве оболочки pathlib

https://github.com/baijifeilong/IceSpringPathLib

pip install IceSpringPathLib

      import pathlib
import tempfile

import chardet

import IceSpringPathLib

tempfile.mktemp()
filename = tempfile.mktemp()
text = "Common\n常\nSense\n识\n天地玄黄"
print("Original text:", repr(text))

pathlib.Path(filename).write_text(text)
encoding = chardet.detect(open(filename, mode="rb").read())["encoding"]
print("\nWritten text by pathlib:", repr(open(filename, newline="", encoding=encoding).read()))
print("Written encoding by pathlib:", encoding)

IceSpringPathLib.Path(filename).write_text(text)
encoding = chardet.detect(open(filename, mode="rb").read())["encoding"]
print("\nWritten text by IceSpringPathLib:", repr(open(filename, newline="", encoding=encoding).read()))
print("Written encoding by IceSpringPathLib:", encoding)

Пример вывода:

      Original text: 'Common\n常\nSense\n识\n天地玄黄'

Written text by pathlib: 'Common\r\n常\r\nSense\r\n识\r\n天地玄黄'
Written encoding by pathlib: GB2312

Written text by IceSpringPathLib: 'Common\n常\nSense\n识\n天地玄黄'
Written encoding by IceSpringPathLib: utf-8

установить кодировку ОС по умолчанию UTF-8. Например, в файле редактирования ubuntu /etc/default/locale и установите:

      LANG=en_US.UTF-8
LANGUAGE=en_US.UTF-8
LC_ALL=en_US.UTF-8

Вы хотите написать испанские слова (para escribir la - en python)

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

print "Piña"
Другие вопросы по тегам