为什么我们不应该在py脚本中使用sys.setdefaultencoding(“utf-8”)?

2024-03-29 07:47:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我见过一些py脚本在脚本顶部使用这个。在什么情况下应该使用它?

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

Tags: pyimport脚本sys情况reloadutfsetdefaultencoding
3条回答
#!/usr/bin/env python
#-*- coding: utf-8 -*-
u = u'moçambique'
print u.encode("utf-8")
print u

chmod +x test.py
./test.py
moçambique
moçambique

./test.py > output.txt
Traceback (most recent call last):
  File "./test.py", line 5, in <module>
    print u
UnicodeEncodeError: 'ascii' codec can't encode character 
u'\xe7' in position 2: ordinal not in range(128)

在shell works上,不发送给sdtout, 所以这是一个解决办法,写信给stdout。

我做了另一个方法,如果没有定义sys.stdout.encoding,或者换句话说,需要先导出pythonionecoding=UTF-8才能写入stdout,则不会运行该方法。

import sys
if (sys.stdout.encoding is None):            
    print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout." 
    exit(1)


所以,用同样的例子:

export PYTHONIOENCODING=UTF-8
./test.py > output.txt

会有用的

tl;博士

答案是永远不要!(除非你真的知道自己在做什么)

9/10倍的解决方案可以通过正确理解编码/解码来解决。

1/10的人的区域设置或环境定义不正确,需要设置:

PYTHONIOENCODING="UTF-8"  

在他们的环境中修复控制台打印问题。

它是做什么的?

sys.setdefaultencoding("utf-8")(删除以避免重复使用)更改每当Python 2.x需要将Unicode()转换为str()时(反之亦然)使用的默认编码/解码,并且不提供编码。一、 e:

str(u"\u20AC")
unicode("€")
"{}".format(u"\u20AC") 

在Python 2.x中,默认编码设置为ASCII,上面的示例将失败:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)

(我的控制台配置为UTF-8,因此"€" = '\xe2\x82\xac',因此\xe2上出现异常)

或者

UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)

sys.setdefaultencoding("utf-8")允许这些为我工作,但不一定为不使用UTF-8的人工作。默认的ASCII可确保编码假设不会烘焙到代码中

控制台

sys.setdefaultencoding("utf-8")还有一个副作用,即在将字符打印到控制台时,似乎可以修复sys.stdout.encoding。Python使用用户的语言环境(Linux/OS X/Un*X)或代码页(Windows)来设置此设置。有时,用户的区域设置被破坏,只需要PYTHONIOENCODING来修复控制台编码。

示例:

$ export LANG=en_GB.gibberish
$ python
>>> import sys
>>> sys.stdout.encoding
'ANSI_X3.4-1968'
>>> print u"\u20AC"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
>>> exit()

$ PYTHONIOENCODING=UTF-8 python
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> print u"\u20AC"
€

sys.setdefaultencoding(“utf-8”)有什么不好的?

16年来,人们一直在开发针对Python2.x的代码,他们的理解是默认编码是ASCII。UnicodeError编写了异常处理方法,以处理在发现包含非ASCII的字符串上进行的字符串到Unicode的转换。

来自https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/

def welcome_message(byte_string):
    try:
        return u"%s runs your business" % byte_string
    except UnicodeError:
        return u"%s runs your business" % unicode(byte_string,
            encoding=detect_encoding(byte_string))

print(welcome_message(u"Angstrom (Å®)".encode("latin-1"))

Previous to setting defaultencoding this code would be unable to decode the “Å” in the ascii encoding and then would enter the exception handler to guess the encoding and properly turn it into unicode. Printing: Angstrom (Å®) runs your business. Once you’ve set the defaultencoding to utf-8 the code will find that the byte_string can be interpreted as utf-8 and so it will mangle the data and return this instead: Angstrom (Ů) runs your business.

更改应该是常量的内容将对依赖的模块产生显著影响。最好是修复进出代码的数据。

示例问题

虽然在下面的示例中,将defaultencoding设置为UTF-8不是根本原因,但它显示了如何掩盖问题,以及当输入编码更改时,代码如何以不明显的方式中断: UnicodeDecodeError: 'utf8' codec can't decode byte 0x80 in position 3131: invalid start byte

根据文档:这允许您从默认的ASCII转换到其他编码,如UTF-8,Python运行时在需要将字符串缓冲区解码为unicode时将使用UTF-8。

此函数仅在Python启动时(Python扫描环境时)可用。它必须在系统范围的模块sitecustomize.py中调用,在对该模块求值之后,将setdefaultencoding()函数从sys模块中移除。

真正使用它的唯一方法是使用一个重新加载hack,将属性带回来。

另外,不鼓励使用sys.setdefaultencoding(),并且它已经成为py3k中的no op。py3k的编码硬连接到“utf-8”并更改它会引起错误。

我建议一些阅读要点:

相关问题 更多 >