185

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

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

4 回答 4

155

根据文档:这允许您从默认 ASCII 切换到其他编码,例如 UTF-8,Python 运行时将在必须将字符串缓冲区解码为 un​​icode 时使用它。

此功能仅在 Python 启动时可用,此时 Python 扫描环境。必须在系统范围的模块中调用它sitecustomize.py,在评估此模块后,setdefaultencoding()从模块中删除该函数sys

实际使用它的唯一方法是使用重新加载技巧来恢复属性。

此外,一直不鼓励使用sys.setdefaultencoding(),它已成为 py3k 中的无操作。py3k 的编码硬连线到“utf-8”,更改它会引发错误。

我建议一些阅读建议:

于 2010-09-30T07:48:37.977 回答
65

tl;博士

答案是从不(除非你真的知道你在做什么)

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

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

PYTHONIOENCODING="UTF-8"  

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

它有什么作用?

sys.setdefaultencoding("utf-8")(为了避免重复使用而删除)更改了 Python 2.x 需要将 Unicode() 转换为 str() (反之亦然)并且未给出编码时使用的默认编码/解码。IE:

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")还有一个副作用是出现 fix 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"))

在设置 defaultencoding 之前,此代码将无法解码 ascii 编码中的“Å”,然后将进入异常处理程序以猜测编码并将其正确转换为 unicode。印刷:Angstrom (Å®) 经营您的业务。将默认编码设置为 utf-8 后,代码会发现 byte_string 可以解释为 utf-8,因此它将破坏数据并返回:Angstrom (Ů) 运行您的业务。

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

示例问题

虽然将 defaultencoding 设置为 UTF-8 不是以下示例中的根本原因,但它显示了如何掩盖问题,以及当输入编码更改时,代码如何以不明显的方式中断: UnicodeDecodeError: 'utf8' codec can 't 解码位置 3131 中的字节 0x80:无效的起始字节

于 2015-12-20T07:49:25.150 回答
19
#!/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 不是,所以这是一种解决方法,写入 stdout 。

我采用了其他方法,如果未定义 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

将工作

于 2011-07-19T03:40:25.537 回答
3
  • 第一个危险在于reload(sys)

    当您重新加载一个模块时,您实际上会在运行时中获得该模块的两个副本。旧模块和其他所有模块一样都是 Python 对象,只要有对它的引用,它就会一直存在。因此,一半的对象将指向旧模块,一半指向新模块。当您进行一些更改时,当某些随机对象没有看到更改时,您将永远不会看到它:

    (This is IPython shell)
    
    In [1]: import sys
    
    In [2]: sys.stdout
    Out[2]: <colorama.ansitowin32.StreamWrapper at 0x3a2aac8>
    
    In [3]: reload(sys)
    <module 'sys' (built-in)>
    
    In [4]: sys.stdout
    Out[4]: <open file '<stdout>', mode 'w' at 0x00000000022E20C0>
    
    In [11]: import IPython.terminal
    
    In [14]: IPython.terminal.interactiveshell.sys.stdout
    Out[14]: <colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
    
  • 现在,sys.setdefaultencoding()

    它所影响的只是隐式转换str<->unicode。现在,utf-8是地球上最合理的编码(向后兼容 ASCII 和所有编码),转换现在“正常工作”,可能会出现什么问题?

    嗯,什么都行。这就是危险。

    • 可能有一些代码依赖于UnicodeError非 ASCII 输入的抛出,或者使用错误处理程序进行转码,现在会产生意外结果。而且由于所有代码都使用默认设置进行了测试,因此您在此处严格处于“不受支持”的领域,并且没有人向您保证他们的代码将如何运行。
    • 如果不是系统上的所有内容都使用 UTF-8,则转码可能会产生意外或不可用的结果,因为 Python 2 实际上有多个独立的“默认字符串编码”。(请记住,程序必须在客户的设备上为客户工作。)
      • Again, the worst thing is you will never know that because the conversion is implicit -- you don't really know when and where it happens. (Python Zen, koan 2 ahoy!) You will never know why (and if) your code works on one system and breaks on another. (Or better yet, works in IDE and breaks in console.)
于 2018-04-21T22:59:42.843 回答