Ответ 1
Мой вопрос в том, почему две переменные кодирования отличаются друг от друга
Они служат для разных целей.
sys.stdout.encoding
должна быть кодировка, используемая вашим терминалом для интерпретации текста, иначе вы можете получить mojibake на выходе. Это может быть utf-8 в одной среде, cp437 в другой и т.д.
sys.getdefaultencoding()
используется на Python 2 для неявных преобразований (когда кодировка не задана явно), то есть Python 2 может смешивать только ascii-значения и строки Unicode, например, xml.etree.ElementTree
сохраняет текст в диапазоне ascii как bytestrings или json.dumps()
возвращает только ascii-версию ascii вместо Unicode в Python 2 - возможно, из-за производительности - байты были дешевле, чем Unicode для представления символов ascii. Неявные преобразования запрещены в Python 3.
sys.getdefaultencoding()
всегда 'ascii'
для всех систем в Python 2, если вы не переопределяете его, что вы не должны делать иначе, это может скрыть ошибки, и ваши данные могут быть легко повреждены из-за неявных преобразований, используя, возможно, неправильную кодировку для данные.
btw, существует еще одна общая кодировка sys.getfilesystemencoding()
, которая может отличаться от двух. sys.getfilesystemencoding()
должна быть кодировка, которая используется для кодирования данных ОС (имена файлов, аргументы командной строки, переменные среды).
Кодировка исходного кода, объявленная с помощью # -*- coding: utf-8 -*-
, может отличаться от всех уже упомянутых кодировок.
Естественно, если вы читаете данные из файла, сети; он может использовать кодировки символов, отличные от указанных выше, например, если файл, созданный в блокноте, сохраняется с использованием кодировки ANSI Windows, такой как cp1252
, а затем в другой системе все стандартные кодировки могут отличаться от нее.
Точка: может быть несколько кодировок по причинам, не связанным с Python, и чтобы избежать головной боли, используйте Unicode для представления текста: конвертируйте как можно скорее кодированный текст в Unicode на входе и закодируйте на байтах (возможно, используя различную кодировку) как можно позже на выходе - это так называется концепция Unicode sandwich.
как мне удастся использовать неправильную кодировку в этом простом коде?
-
Ваш первый пример кода не подходит. Вы используете не-ascii буквенные символы в байтовой строке на Python 2, которую вы не должны делать. Используйте литералы bytestrings только для двоичных данных (или, если необходимо, так называемых родных строк). Код может создавать mojibake, например
I need 20 000Γé¼.
(обратите внимание на характерный шум), если вы запускаете его с помощью Python 2 в любой среде, которая не использует кодировку, совместимую с utf-8, например консоль Windows -
Второй пример кода одобрен, если
reload(sys)
не является его частью. Если вы не хотите префикс всех строковых литералов с помощьюu''
; вы можете использоватьfrom __future__ import unicode_literals
Ваша фактическая проблема - ошибка UnicodeEncodeError
, а reload(sys)
- неправильное решение!
Правильное решение правильно настроить вашу локаль на POSIX (LANG
, LC_CTYPE
) или установить PYTHONIOENCODING
envvar если выход перенаправляется на канал/файл или устанавливается win-unicode-console
для печати консоли Unicode в Windows.