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

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

import sys
reload(sys)
sys.setdefaultencoding("utf-8")
231962 次浏览

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

这个函数只在 Python 启动时可用,当 Python 扫描环境时。它必须在一个系统范围的模块 sitecustomize.py中调用,在对这个模块进行评估之后,从 sys模块中删除 setdefaultencoding()函数。

实际使用它的唯一方法是通过重新加载黑客技术将属性恢复。

还有 sys.setdefaultencoding()的使用一直是不被鼓励的,它已经成为 py3k 中的禁止操作。Py3k 的编码是硬连接到“ utf-8”的,更改它会产生错误。

我建议一些阅读指南:

#!/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)

在外壳工程,发送到斯达特不, 所以这是一个变通方法,写入标准输出。

我使用了其他方法,如果 sys.stdout.coding 没有定义,或者换句话说,需要首先导出 PYTHONIOENCOding = 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

会成功的

博士

答案是 从来没有! (除非你真的知道自己在做什么)

只要正确理解编码/解码,就可以解决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)

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"
€

Setdefaultencoding (“ utf-8”)有什么不好?

基于默认编码是 ASCII 的理解,人们已经针对 Python 2.x 开发了16年。已经编写了 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 经营你的生意。一旦您将缺省编码设置为 utf-8,代码将发现 byte _ string 可以被解释为 utf-8,因此它将破坏数据并返回这个: Angstrom ()运行您的业务。

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

例题

虽然默认编码设置为 UTF-8并不是下面例子中的根本原因,但它显示了问题是如何被掩盖的,以及当输入编码发生变化时,代码是如何以一种不明显的方式中断的: UnicodeDecodeError: utf8 & # 39; codec can & # 39; t decode byte 0x80 in position 3131: 無效起始字节

  • 第一个危险在于 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>
    
  • Now, sys.setdefaultencoding() proper

    All that it affects is implicit conversion str<->unicode. Now, utf-8 is the sanest encoding on the planet (backward-compatible with ASCII and all), the conversion now "just works", what could possibly go wrong?

    Well, anything. And that is the danger.

    • There may be some code that relies on the UnicodeError being thrown for non-ASCII input, or does the transcoding with an error handler, which now produces an unexpected result. And since all code is tested with the default setting, you're strictly on "unsupported" territory here, and no-one gives you guarantees about how their code will behave.
    • The transcoding may produce unexpected or unusable results if not everything on the system uses UTF-8 because Python 2 actually has multiple independent "default string encodings". (Remember, a program must work for the customer, on the customer's equipment.)
      • 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.)