为什么我们不应该在py脚本中使用sys.setdefaultencoding(“utf-8”)?
我已经看到在脚本的顶部使用这个脚本的几个py脚本。 在什么情况下应该使用它?
import sys reload(sys) sys.setdefaultencoding("utf-8")
根据文档:这允许您从默认的ASCII切换到其他编码,如UTF-8,Python运行时将需要使用的编码解码字符串缓冲区unicode。
这个函数只有在Python启动的时候,Python才能扫描环境。 必须在系统范围的模块sitecustomize.py
,在对该模块进行了评估之后,将从sys
模块中删除setdefaultencoding()
函数。
实际使用它的唯一方法是重新加载hack,使属性恢复。
此外, 使用sys.setdefaultencoding()
一直是不鼓励的 ,它已经成为py3k中没有任何操作。 py3k的编码被硬连线到“utf-8”,改变它会产生一个错误。
我建议读一些指针:
- http://blog.ianbicking.org/illusive-setdefaultencoding.html
- http://nedbatchelder.com/blog/200401/printing_unicode_from_python.html
- http://www.diveintopython3.net/strings.html#one-ring-to-rule-them-all
- http://boodebr.org/main/python/all-about-python-and-unicode
- http://blog.notdot.net/2010/07/Getting-unicode-right-in-Python
TL;博士
答案永远不会 ! (除非你真的知道你在做什么)
解决方案的9/10倍可以通过正确理解编码/解码来解决。
1/10的人有一个不正确的区域设置或环境,需要设置:
PYTHONIOENCODING="UTF-8"
在他们的环境中修复控制台打印问题。
它有什么作用?
(避免重复使用)改变了Python 2.x需要将Unicode()转换为str()(反之亦然)时使用的默认编码/解码。没有给出编码。 即: sys.setdefaultencoding("utf-8")
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)
将允许这些为我工作,但不一定会为不使用UTF-8的人工作。 ASCII的默认值确保编码的假设不被烘焙到代码中 sys.setdefaultencoding("utf-8")
安慰
也有一个副作用,出现在修复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年的Python 2.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"))
在设置默认编码之前,此代码将无法解码ascii编码中的“Å”,然后进入异常处理程序来猜测编码并将其正确地转换为unicode。 印刷:Angstrom(Å®)经营您的业务。 一旦将defaultencoding设置为utf-8,代码就会发现byte_string可以被解释为utf-8,所以它会破坏数据并返回这个数据:Angstrom(Ů)运行你的业务。
改变应该是一个常数将会对你所依赖的模块产生巨大的影响。 最好是修正进出代码的数据。
示例问题
虽然UTF-8的默认编码设置不是下面例子中的根本原因,但它显示了如何屏蔽问题以及如何在输入编码更改时以不明显的方式中断代码: UnicodeDecodeError:“utf8”编解码器可以在位置3131解码字节0x80:无效起始字节
#!/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的作品,发送到sdtout不,所以这是一个解决方法,写入标准输出。
我提出了另一种方法,如果sys.stdout.encoding没有定义,那么这个方法就不会运行,或者换句话说,首先需要导出PYTHONIOENCODING = UTF-8才能写入标准输出。
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
将工作
你可以在python3中使用编解码器模块。 例如
import codecs fopen = codecs.open('file_name.txt', 'r', 'UTF-8')