小编典典

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

python

我花了几个小时来寻找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)

阅读 223

收藏
2020-12-20

共1个答案

小编典典

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

它们有不同的用途。

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

sys.getdefaultencoding()在Python 2上用于隐式转换(未明确设置编码时),即Python
2可以将仅ascii的字节字符串和Unicode字符串混合在一起,例如,xml.etree.ElementTree将ascii范围内的文本存储为字节字符串,或者json.dumps()返回仅ascii的字节字符串而不是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文字字符。仅将字节字符串的文字用于二进制数据(或在必要时使用本机字符串)。I need 20 000Γé¼.如果您在任何不使用utf-8兼容编码的环境(例如Windows控制台)中使用Python 2运行该代码,则该代码可能会产生mojibake,例如(注意字符噪声)

  2. 假设第二个代码示例reload(sys)不包含在其中,则可以。如果您不想在所有字符串文字前添加u''; 你可以用from __future__ import unicode_literals

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

2020-12-20