为什么sys.getdefaultencoding()与sys.stdout.encoding不同?它如何破坏Unicode字符串?

Ale*_*kov 8 python stdout utf sys

我花了几个小时的时间来寻找Unicode字符串的问题,这些字符串被分解为Python(2.7)隐藏的东西,我仍然不明白.首先,我尝试u".."在我的代码中使用一致的字符串,但这导致臭名昭着UnicodeEncodeError.我尝试过使用.encode('utf8'),但这也无济于事.最后,事实证明我不应该使用任何一个,它都可以自动完成.然而,我(这里我需要赞扬一位帮助过我的朋友)确实注意到一些奇怪的事情,同时我的头靠在墙上.sys.getdefaultencoding()返回ascii,同时sys.stdout.encoding返回UTF-8.1.在下面的代码中工作正常,没有任何修改sys和2.提出一个UnicodeEncodeError.如果我更改默认的系统编码 reload(sys).setdefaultencoding("utf8"),那么2.工作正常.我的问题是为什么两个编码变量首先是不同的,如何在这段简单的代码中设法使用错误的编码?请不要把我发送到Unicode HOWTO,我已经在很多问题中看到了这一点UnicodeEncodeError.

#  -*- coding: utf-8 -*-
import sys


class Token:
    def __init__(self, string, final=False):
        self.value = string
        self.final = final

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value

print(sys.getdefaultencoding())
print(sys.stdout.encoding)

# 1.
myString = "I need 20 000€."
tok = Token(myString)
print(tok)

reload(sys).setdefaultencoding("utf8")

# 2.
myString = u"I need 20 000€."
tok = Token(myString)
print(tok)
Run Code Online (Sandbox Code Playgroud)

jfs*_*jfs 5

我的问题是为什么两个编码变量首先是不同的

它们用于不同的目的.

sys.stdout.encoding应该是您的终端用于解释文本的编码,否则您可能会在输出中获得mojibake.在一个环境中可能是utf-8,在另一个环境中可能是cp437,等等.

sys.getdefaultencoding()在Python 2上用于隐式转换(当未明确设置编码时),即,Python 2可以将ascii-only字符串和Unicode字符串混合在一起,例如,xml.etree.ElementTree将ascii范围内的文本存储为bytestrings或json.dumps()返回ascii-only字节字符串而不是Unicode在Python 2中 - 可能由于性能 - 字节比用于表示ascii字符的Unicode便宜.Python 3中禁止隐式转换.

sys.getdefaultencoding()永远'ascii'在Python 2中的所有系统上,除非你覆盖它,否则它可能会隐藏错误,并且由于使用可能错误的数据编码的隐式转换,您的数据可能很容易被破坏.

顺便说一句,还有另一种常见的编码sys.getfilesystemencoding()可能与两者不同.sys.getfilesystemencoding()应该是用于编码OS数据的编码(文件名,命令行参数,环境变量).

声明使用的源代码编码# -*- coding: utf-8 -*-可能与所有已提到的编码不同.

当然,如果您从文件,网络中读取数据; 它可以使用与上述不同的字符编码,例如,如果使用Windows ANSI编码保存在记事本中创建的文件,例如cp1252在另一个系统上,则所有标准编码都可以与之不同.

重点是:由于与Python无关的原因可能存在多种编码并避免头痛,使用Unicode表示文本:在输入时尽快将编码文本转换为Unicode,并将其编码为字节(可能使用不同的编码)尽可能晚地输出 - 这就是所谓的Unicode三明治的概念.

如何在这段简单的代码中设法使用错误的编码?

  1. 你的第一个代码示例不是很好.您在Python 2上的字节字符串中使用非ascii文字字符,您不应该这样做.仅对二进制数据使用bytestrings的文字(如果需要,可以使用所谓的本机字符串).I need 20 000?é¼.如果您在任何不使用utf-8兼容编码的环境(例如Windows控制台)中使用Python 2运行它,代码可能会产生mojibake,例如(注意字符噪音)

  2. 第二个代码示例是ok,假设reload(sys)不是它的一部分.如果您不想为所有字符串文字添加前缀u''; 你可以用from __future__ import unicode_literals

您的实际问题是UnicodeEncodeError错误,reload(sys)并不是正确的解决方案!
正确的解决方案是在POSIX(LANG,LC_CTYPE)上正确配置您的语言环境,或者如果输出重定向到管道/文件,则设置PYTHONIOENCODINGenvvar或安装win-unicode-console以将Unicode打印到Windows控制台.