改变 Python 的默认编码?

2024-12-04 08:56:00
admin
原创
150
摘要:问题描述:当我从控制台运行Python应用程序时,我遇到了许多“无法编码”和“无法解码”的问题。但在Eclipse PyDev IDE 中,默认字符编码设置为UTF-8,我没问题。我到处搜索如何设置默认编码,有人说 Pythonsys.setdefaultencoding在启动时会删除该函数,我们无法使用它。...

问题描述:

当我从控制台运行Python应用程序时,我遇到了许多“无法编码”和“无法解码”的问题。但在Eclipse PyDev IDE 中,默认字符编码设置为UTF-8,我没问题。

我到处搜索如何设置默认编码,有人说 Pythonsys.setdefaultencoding在启动时会删除该函数,我们无法使用它。

那么最好的解决方案是什么?


解决方案 1:

这是一个更简单的方法(hack),可以让你返回setdefaultencoding()从中删除的功能sys

import sys
# sys.setdefaultencoding() does not exist, here!
reload(sys)  # Reload does the trick!
sys.setdefaultencoding('UTF8')

(Python 3.4+注意事项:reload()importlib库中。)

但这样做并不安全:这显然是一种黑客行为,因为Python 启动时sys.setdefaultencoding()会故意将其删除sys。重新启用它并更改默认编码可能会破坏依赖 ASCII 作为默认代码的代码(此代码可能是第三方的,这通常会使修复它变得不可能或危险)。

PS:这个 hack 似乎不再适用于 Python 3.9。

解决方案 2:

如果你在尝试管道/重定向脚本输出时收到此错误

UnicodeEncodeError:'ascii'编解码器无法对位置 0-5 的字符进行编码:序数不在范围内(128)

只需在控制台中导出PYTHONIOENCODING,然后运行您的代码。

export PYTHONIOENCODING=utf8

解决方案 3:

A)控制sys.getdefaultencoding()输出:

python -c 'import sys; print(sys.getdefaultencoding())'

ascii

然后

echo "import sys; sys.setdefaultencoding('utf-16-be')" > sitecustomize.py

PYTHONPATH=".:$PYTHONPATH" python -c 'import sys; print(sys.getdefaultencoding())'

utf-16-be

您可以将sitecustomize.py放在 的更高位置PYTHONPATH

你也可以尝试reload(sys).setdefaultencoding@EOL

B)要控制stdin.encodingstdout.encoding设置PYTHONIOENCODING

python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'

ascii ascii

然后

PYTHONIOENCODING="utf-16-be" python -c 'import sys; 
print(sys.stdin.encoding, sys.stdout.encoding)'

utf-16-be utf-16-be

最后:您可以使用A)B)两者!

解决方案 4:

从PyDev 3.4.1 开始,默认编码不再改变。有关详细信息,请参阅此票。

对于早期版本,解决方案是确保 PyDev 不以 UTF-8 作为默认编码运行。在 Eclipse 下,运行对话框设置(如果我没记错的话,是“运行配置”);您可以在公共选项卡上选择默认编码。如果您想“尽早”出现这些错误(换句话说:在您的 PyDev 环境中),请将其更改为 US-ASCII。另请参阅有关此解决方法的原始博客文章。

解决方案 5:

关于 python2 (仅限 python2),一些前面的答案依赖于使用以下 hack:

import sys
reload(sys)  # Reload is a hack
sys.setdefaultencoding('UTF8')

不鼓励使用它(检查这个或这个)

就我而言,它有一个副作用:我使用的是 ipython 笔记本,一旦我运行代码,“print”函数就不再起作用了。我想应该有解决办法,但我仍然认为使用 hack 不是正确的选择。

尝试了许多选项之后,对我有用的选项是在 中使用相同的代码sitecustomize.py,其中该代码段应该是。评估该模块后,setdefaultencoding 函数将从 sys 中删除。

因此解决方案是将/usr/lib/python2.7/sitecustomize.py代码附加到文件:

import sys
sys.setdefaultencoding('UTF8')

当我使用 virtualenvwrapper 时,我编辑的文件是~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py

当我使用 python 笔记本和 conda 时,它是~/anaconda2/lib/python2.7/sitecustomize.py

解决方案 6:

有一篇关于此的深刻博客文章。

请参阅https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/

下面我将其内容解释如下。

在 Python 2 中,字符串编码类型不是那么强,您可以对不同编码的字符串执行操作并成功。例如,以下内容将返回True

u'Toshio' == 'Toshio'

这对于以 编码的每个(正常的、无前缀的)字符串都适用sys.getdefaultencoding(),默认为ascii,但不适用于其他字符串。

默认编码旨在在 中在系统范围内更改site.py,而不是在其他地方。在用户模块中设置它的技巧(也在此处介绍)只是技巧,而不是解决方案。

Python 3 确实将系统编码改为默认为 utf-8(当 LC_CTYPE 支持 unicode 时),但根本问题已通过在与 unicode 字符串一起使用时明确编码“字节”字符串的要求得到解决。

解决方案 7:

这是我用来生成与python2python3兼容且始终生成utf8输出的代码的方法。我在其他地方找到了这个答案,但我不记得来源了。

这种方法的工作原理是使用一些不太像文件的sys.stdout东西来替换(但仍然只使用标准库中的东西)。这很可能会给您的底层库带来问题,但在您可以很好地控制 sys.stdout 如何在框架中使用的情况下,这可能是一种合理的方法。

sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')

解决方案 8:

首先:reload(sys)仅仅为了输出终端流的需要而设置一些随机的默认编码是不好的做法。reload通常会根据环境更改 sys 中已经设置的内容 - 例如 sys.stdin/stdout 流、sys.excepthook 等。

解决 stdout 上的编码问题

我所知道的解决sys.stdout 上的printunicode 字符串和 beyond-ascii str(例如来自文字)的编码问题的最佳解决方案是:处理一个 sys.stdout (类似文件的对象),它能够满足以下需求并且可以选择容忍:

  • sys.stdout.encoding由于None某种原因,或不存在,或错误地为假,或“小于”stdout终端或流的实际能力时,则尝试提供正确的.encoding属性。最后通过替换sys.stdout & sys.stderr为翻译文件类对象。

  • 当终端 / 流仍然无法对所有出现的unicode字符进行编码时,并且您不想print因此而破坏 ,您可以在翻译类文件对象中引入编码替换行为。

下面是一个例子:

#!/usr/bin/env python
# encoding: utf-8
import sys

class SmartStdout:
    def __init__(self, encoding=None, org_stdout=None):
        if org_stdout is None:
            org_stdout = getattr(sys.stdout, 'org_stdout', sys.stdout)
        self.org_stdout = org_stdout
        self.encoding = encoding or \n                        getattr(org_stdout, 'encoding', None) or 'utf-8'
    def write(self, s):
        self.org_stdout.write(s.encode(self.encoding, 'backslashreplace'))
    def __getattr__(self, name):
        return getattr(self.org_stdout, name)

if __name__ == '__main__':
    if sys.stdout.isatty():
        sys.stdout = sys.stderr = SmartStdout()

    us = u'aouäöüфżß²'
    print us
    sys.stdout.flush()

在 Python 2 / 2 + 3 代码中使用 beyond-ascii 纯字符串文字

我认为更改全局默认编码(仅更改为 UTF-8)的唯一好理由是关于应用程序源代码决策 - 而不是因为 I/O 流编码问题:为了将超出 ascii 的字符串文字写入代码,而不必始终使用u'string'样式 unicode 转义。这可以相当一致地完成(尽管anonbadger的文章这么说),通过处理一致使用 ascii 或 UTF-8 纯字符串文字的 Python 2 或 Python 2 + 3 源代码基础 - 只要这些字符串可能经历静默 unicode 转换并在模块之间移动或可能转到 stdout。为此,最好使用“ # encoding: utf-8”或 ascii(无声明)。更改或删除仍然以非常愚蠢的方式致命地依赖于超出 chr #127 的 ascii 默认编码错误的库(这在今天很少见)。

除了上述方案之外,在应用程序启动时(和/或通过 sitecustomize.py)执行SmartStdout以下操作 - 无需使用reload(sys)

...
def set_defaultencoding_globally(encoding='utf-8'):
    assert sys.getdefaultencoding() in ('ascii', 'mbcs', encoding)
    import imp
    _sys_org = imp.load_dynamic('_sys_org', 'sys')
    _sys_org.setdefaultencoding(encoding)

if __name__ == '__main__':
    sys.stdout = sys.stderr = SmartStdout()
    set_defaultencoding_globally('utf-8') 
    s = 'aouäöüфżß²'
    print s

这样,字符串文字和大多数操作(字符迭代除外)都可以顺利运行,而无需考虑 unicode 转换,就像只有 Python3 一样。当然,文件 I/O 总是需要特别注意编码 - 就像在 Python3 中一样。

SmartStdout注意:在转换为输出流编码之前,纯文本字符串会被隐式地从 utf-8 转换为 unicode 。

解决方案 9:

这是一种快速破解方法,适用于以下任何人:(1) 在 Windows 平台上 (2) 运行 Python 2.7 并且 (3) 因为一个不错的软件(即不是你编写的,因此不是立即用于编码/解码打印操作的候选)不会显示“漂亮的 unicode 字符”在 IDLE 环境中(Pythonwin 可以很好地打印 unicode),例如,Stephan Boyer 在他的教学证明器(在First Order Logic Prover )的输出中使用的整洁的一阶逻辑符号。

我不喜欢强制重新加载系统的想法,而且我无法让系统配合设置环境变量,比如 PYTHONIOENCODING(尝试直接使用 Windows 环境变量,并将其放在站点包中的 sitecustomize.py 中,作为一个行 ='utf-8')。

因此,如果您愿意通过黑客手段获得成功,请转到 IDLE 目录,通常是:“C:\Python27\Lib\idlelib” 找到文件 IOBinding.py。复制该文件并将其存储在其他位置,以便您可以在选择时恢复到原始行为。使用编辑器(例如 IDLE)打开 idlelib 中的文件。转到此代码区域:

# Encoding for file names
filesystemencoding = sys.getfilesystemencoding()

encoding = "ascii"
if sys.platform == 'win32':
    # On Windows, we could use "mbcs". However, to give the user
    # a portable encoding name, we need to find the code page 
    try:
        # --> 6/5/17 hack to force IDLE to display utf-8 rather than cp1252
        # --> encoding = locale.getdefaultlocale()[1]
        encoding = 'utf-8'
        codecs.lookup(encoding)
    except LookupError:
        pass

换句话说,注释掉' try '后面的原始代码行,该代码行使编码变量等于locale.getdefaultlocale(因为这将给您您不想要的cp1252),而是强制将其转换为'utf-8'(通过添加行' encoding ='utf-8 ',如图所示)。

我相信这只会影响 IDLE 向 stdout 的显示,而不会影响文件名等的编码(这是在之前的 filesystemencoding 中获得的)。如果您稍后在 IDLE 中运行的任何其他代码有问题,只需将 IOBinding.py 文件替换为原始未修改的文件即可。

解决方案 10:

你可以更改整个操作系统的编码。在 Ubuntu 上,你可以使用以下命令执行此操作

sudo apt install locales 
sudo locale-gen en_US en_US.UTF-8    
sudo dpkg-reconfigure locales

解决方案 11:

windows设置环境变量
PYTHONUTF8=1

解决方案 12:

将操作系统的默认编码设置为UTF-8。例如,在 ubuntu 上编辑文件/etc/default/locale并设置:

LANG=en_US.UTF-8
LANGUAGE=en_US.UTF-8
LC_ALL=en_US.UTF-8

解决方案 13:

如果您只希望UTF-8文件上有稳定的支持read/write不需要到处都有相同的声明,那么有两种解决方案:

1.运行时修补io模块(危险操作,风险自负)

import pathlib as pathlib
import tempfile

import chardet


def patchIOWithUtf8Default():
    import builtins
    import importlib.util
    import sys
    spec = importlib.util.find_spec("io")
    module = importlib.util.module_from_spec(spec)
    exec(compile(spec.loader.get_source(spec.name) + """
    def open(*args, **kwargs):
        args = list(args)
        mode = kwargs.get('mode', (args + [''])[1])
        if (len(args) < 4 and 'b' not in mode) or 'encoding' in kwargs:
            kwargs['encoding'] = 'utf8'
        elif len(args) >= 4 and args[3] is None:
            args[3] = 'utf8'
        return _io.open(*args, **kwargs)
    """, module.__spec__.origin, "exec"), module.__dict__)
    sys.modules[module.__name__] = module
    builtins.open = __import__("io").open
    importlib.reload(importlib.import_module("pathlib"))


def main():
    patchIOWithUtf8Default()
    filename = tempfile.mktemp()
    text = "Common
常
Sense
识
天地玄黄"
    print("Original text:", repr(text))
    pathlib.Path(filename).write_text(text)
    encoding = chardet.detect(open(filename, mode="rb").read())["encoding"]
    print("Written encoding by pathlib:", encoding)
    print("Written text by pathlib:", repr(open(filename, newline="", encoding=encoding).read()))


if __name__ == '__main__':
    main()

示例输出:

Original text: 'Common
常
Sense
识
天地玄黄'
Written encoding by pathlib: utf-8
Written text by pathlib: 'Common
常
Sense
识
天地玄黄'

2. 使用第三个库作为 pathlib 包装器

https://github.com/baijifeilong/IceSpringPathLib

pip install IceSpringPathLib

import pathlib
import tempfile

import chardet

import IceSpringPathLib

tempfile.mktemp()
filename = tempfile.mktemp()
text = "Common
常
Sense
识
天地玄黄"
print("Original text:", repr(text))

pathlib.Path(filename).write_text(text)
encoding = chardet.detect(open(filename, mode="rb").read())["encoding"]
print("
Written text by pathlib:", repr(open(filename, newline="", encoding=encoding).read()))
print("Written encoding by pathlib:", encoding)

IceSpringPathLib.Path(filename).write_text(text)
encoding = chardet.detect(open(filename, mode="rb").read())["encoding"]
print("
Written text by IceSpringPathLib:", repr(open(filename, newline="", encoding=encoding).read()))
print("Written encoding by IceSpringPathLib:", encoding)

示例输出:

Original text: 'Common
常
Sense
识
天地玄黄'

Written text by pathlib: 'Common
常
Sense
识
天地玄黄'
Written encoding by pathlib: GB2312

Written text by IceSpringPathLib: 'Common
常
Sense
识
天地玄黄'
Written encoding by IceSpringPathLib: utf-8

解决方案 14:

这为我解决了这个问题。

import os
os.environ["PYTHONIOENCODING"] = "utf-8"
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用