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

2024-12-16 08:35:00
admin
原创
151
摘要:问题描述:我见过一些 py 脚本在脚本顶部使用它。在什么情况下应该使用它?import sys reload(sys) sys.setdefaultencoding("utf-8") 解决方案 1:根据文档:这允许您从默认的 ASCII 切换到其他编码(例如 UTF-8),每当 Pytho...

问题描述:

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

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

解决方案 1:

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

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

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

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

我建议阅读以下几点:

解决方案 2:

总结

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

9/10 的时候,只要正确理解编码/解码,就可以解决问题。

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

PYTHONIOENCODING="UTF-8"  

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

它起什么作用?

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

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,因此"€" = 'xe2x82xac',因此 出现异常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,即在将字符打印到控制台时会显示为 fix 。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 (Å®) 经营您的业务。将 defaultencoding 设置为 utf-8 后,代码会发现 byte_string 可以解释为 utf-8,因此它会破坏数据并返回此内容:Angstrom (Ů) 经营您的业务。

更改本应为常量的内容将对您依赖的模块产生巨大影响。最好只修复代码中传入和传出的数据。

示例问题

虽然将默认编码设置为 UTF-8 不是以下示例中的根本原因,但它显示了问题是如何被掩盖的,以及当输入编码发生变化时,代码如何以不明显的方式中断:
UnicodeDecodeError:'utf8' 编解码器无法解码位置 3131 中的字节 0x80:无效的起始字节

解决方案 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 上可以工作,但不能发送到 sdtout,因此有一个解决方法,即写入 stdout。

我采用了其他方法,如果 sys.stdout.encoding 未定义,则不会运行该方法,换句话说,需要先导出 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

会起作用

解决方案 4:

  • 第一个危险在于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 实际上具有多个独立的“默认字符串编码”。 (请记住,程序必须为客户在其设备上工作。)


    - 再说一遍,最糟糕的是**你永远不会知道,*因为转换是隐式的*——你真的不知道它何时何地发生。**(Python Zen,koan 2 ahoy!)你永远不会知道为什么(以及是否)你的代码在一个系统上运行而在另一个系统上中断。(或者更好的是,在 IDE 中运行但在控制台中中断。)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1603  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1369  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   30  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   28  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   35  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用