Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python sys.setdefaultencoding(';utf-8';)的危险_Python_Encoding_Utf 8_Python 2.x - Fatal编程技术网

Python sys.setdefaultencoding(';utf-8';)的危险

Python sys.setdefaultencoding(';utf-8';)的危险,python,encoding,utf-8,python-2.x,Python,Encoding,Utf 8,Python 2.x,在Python2中,有一种趋势是不鼓励设置sys.setdefaultencoding('utf-8')。有人能列举出这方面问题的真实例子吗?像它是有害的或它隐藏bug这样的论点听起来不太令人信服 更新:请注意,此问题仅涉及utf-8,而不是“在一般情况下”更改默认编码 如果可以,请给出一些代码示例 实词示例#1 它在单元测试中不起作用 测试运行程序(nose,py.test,…)首先初始化sys,然后才发现并导入模块。到那时,更改默认编码已经太晚了 出于同样的优点,如果有人将代码作为模块运行,

在Python2中,有一种趋势是不鼓励设置
sys.setdefaultencoding('utf-8')
。有人能列举出这方面问题的真实例子吗?像
它是有害的
它隐藏bug
这样的论点听起来不太令人信服

更新:请注意,此问题仅涉及
utf-8
,而不是“在一般情况下”更改默认编码

如果可以,请给出一些代码示例

实词示例#1

它在单元测试中不起作用

测试运行程序(
nose
py.test
,…)首先初始化
sys
,然后才发现并导入模块。到那时,更改默认编码已经太晚了

出于同样的优点,如果有人将代码作为模块运行,这是行不通的,因为他们的初始化是第一位的


是的,混合使用
str
unicode
以及依赖隐式转换只会将问题推向更深的层次。

首先:许多反对更改默认enc的人认为,它之所以愚蠢是因为

我认为,公平地说,按照最初的问题,我认为除了偏离Ascii到UTF-8之外,没有人主张其他任何东西

setdefaultencoding('utf-16')示例似乎总是由那些反对更改它的人提出;-)


使用m={'a':1,'e':2}和文件'out.py':

# coding: utf-8
print u'é' 
然后:

[*]:结果假设相同。请参见下文

在查看这些操作时,更改程序中的默认编码可能看起来不太糟糕,这样您的结果“更接近”只有Ascii数据

关于散列(in)和len()行为,您可以得到与Ascii相同的结果(更多关于下面的结果)。这些操作还表明unicode和字节字符串之间存在显著差异,如果您忽略这些差异,可能会导致逻辑错误

如前所述:它是一个进程范围的选项,因此您只有一次机会来选择它-这就是为什么库开发人员永远不应该这样做,而是将其内部进行整理,这样他们就不需要依赖python的隐式转换。 他们还需要清楚地记录他们期望的内容,并返回和拒绝他们没有编写lib的输入(如normalize函数,见下文)

=>使用该设置编写程序会使其他人在其代码中使用您程序的模块,至少在不过滤输入的情况下,这样做是有风险的

注意:一些反对者声称def.enc。甚至是一个系统范围的选项(通过sitecustomize.py),但在软件容器化(docker)时代是最新的。每个进程都可以在其完美的环境中启动,而不需要额外的开销


关于散列和len()行为:

它告诉您,即使修改了def.enc。您仍然不能对程序中处理的字符串类型一无所知。u“”和“”是内存中不同的字节序列-不总是,但通常是

因此,在测试时,请确保您的程序在使用非Ascii数据时也能正常运行

有人说,当数据值更改时,哈希值可能变得不相等(尽管由于隐式转换,“==”操作保持相等),这是反对更改def.enc的一个理由

我个人不同意这一点,因为散列行为只是保持不变,不改变它。我还没有看到一个令人信服的例子,说明在我“拥有”的过程中,由于该设置而产生的不受欢迎的行为

总而言之,关于setdefaultencoding(“utf-8”):关于它是否哑的答案应该更加平衡

视情况而定。 虽然它确实避免了崩溃,例如日志语句中的str()操作,但由于错误的类型会使代码的正确运行取决于特定类型,因此以后出现意外结果的可能性更高

在任何情况下,它都不应该是学习您自己代码的字节字符串和unicode字符串之间的差异的替代方法


最后,将默认编码设置为远离Ascii并不会使常见的文本操作(如len()、切片和比较)变得更容易—您应该假设,使用UTF-8进行字符串化可以解决这里的问题

不幸的是,一般来说,情况并非如此

“==”和len()结果比人们想象的要复杂得多,但即使两边的类型都相同

不带def.enc。已更改,对于非Ascii,“==”始终失败,如表中所示。有了它,它就起作用了——有时:

Unicode确实对世界上大约一百万个符号进行了标准化,并给了它们一个数字——但不幸的是,在输出设备中显示给用户的字形与生成它们的符号之间没有1:1的双射

激励您:有两个文件,j1和j2,使用相同的程序编写,使用相同的编码,包含用户输入:

>>> u1, u2 = open('j1').read(), open('j2').read()
>>> print sys.version.split()[0], u1, u2, u1 == u2
结果:2.7.9何塞·何塞́假(!)

在Py2中使用print作为函数,您可以看到原因:不幸的是,有两种方法可以对同一字符进行编码,即重音“e”:

>>> print (sys.version.split()[0], u1, u2, u1 == u2)
('2.7.9', 'Jos\xc3\xa9', 'Jose\xcc\x81', False)
你可能会说这是一个多么愚蠢的编解码器,但这不是编解码器的错。这是unicode本身的一个问题

因此,即使在Py3中:

>>> u1, u2 = open('j1').read(), open('j2').read()
>>> print sys.version.split()[0], u1, u2, u1 == u2
结果:3.4.2何塞́假(!)

=>独立于Py2和Py3,实际上独立于您使用的任何计算语言:要编写高质量的软件,您可能必须“规范化”所有用户输入。unicode标准实现了标准化。 在Python2和Python3中,unicodedata.normalize函数是您的朋友。

因为您并不总是希望将字符串自动解码为Unicode,也不希望Unicode对象自动编码为字节。因为您要求的是一个具体的例子,这里有一个:

以wsgiweb应用程序为例;你是buildi
>>> u1, u2 = open('j1').read(), open('j2').read()
>>> print sys.version.split()[0], u1, u2, u1 == u2
results = []
content_length = 0

for somevar in some_iterable:
    output = some_process_that_produces_utf8(somevar)
    content_length += len(output)
    results.append(output)

headers = {
    'Content-Length': str(content_length),
    'Content-Type': 'text/html; charset=utf8',
}
start_response(200, headers)
return results
results = []
content_length = 0

for somevar in some_iterable:
    label = translations.get_label(somevar)
    output = some_process_that_produces_utf8(somevar)

    content_length += len(label) + len(output) + 1
    results.append(label + '\n')
    results.append(output)

headers = {
    'Content-Length': str(content_length),
    'Content-Type': 'text/html; charset=utf8',
}
start_response(200, headers)
return results
 >>> from 褐褑褒褓褔褕褖褗褘 import *        
 >>> def 空手(合氣道): あいき(ど(合氣道))
 >>> 空手(う힑힜('One thing we should know is

Python 2 use
sys.getdefaultencoding()
to decode/encode between
str
and
unicode

conversion between str and unicode

so if we change default encoding, there will be all kinds of incompatible issues. eg:

# coding: utf-8
import sys

print "你好" == u"你好"
# False

reload(sys)
sys.setdefaultencoding("utf-8")

print "你好" == u"你好"
# True