将python3设置为脚本的latin-1默认值



TL;DR:我能让Python3使用unicode以外的任何东西作为所有东西的默认编码吗?

我有一些用Python 3编写的脚本。在操作我自己的文件时,它们工作得很好,因为这些文件是用utf-8编码的,而且通常只使用ASCII兼容的子集。

现在,我尝试在已有几十年历史的源文件上使用相同的脚本,结果左右都出现了unicode异常。完全有可能的是,编辑人员在一年中对文件进行了编辑,假设编码不同,因此每个文件的编码可能不同,甚至定义不清。

如果我用Python 2编写脚本,它假设采用固定宽度编码,那么一切都会很好。使用非ascii字符的部分无论如何都只在注释中。

在Python3中,当编码未知且可能定义不清时,干净的解决方案是只对字节数组数据进行操作,但缺少.format函数以及需要在各处区分字节和str文本,这既是语法上的噩梦,而且太耗时,无法在我的脚本中进行修复,因此不值得。

是否可以将假定的默认编码sys.stdin、sys.stderr和所有没有显式编码的文件open ed更改为固定宽度编码?这样做将允许我的脚本以"字节输入,字节输出"的方式工作,这将更适合我对shell脚本的使用(并且最终会更稳定)。

理想情况下,解决方案应该是基于每个脚本的,并允许忽略环境变量。

基于https://stackoverflow.com/a/12823030/2075630是

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="latin-1")
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="latin-1")
sys.stdin  = io.TextIOWrapper(sys.stdin.buffer,  encoding="latin-1")
# To avoid changing individual `open` calls: 
open_ = open
def open(*a,**b):
    b["encoding"] = "latin-1"
    return open_(*a,**b)

但这会导致STDOUT和STDERR流被大量缓冲,这对于shell脚本来说是不可取的。

Python 2不采用任何编码。它基本上是在字节上操作的。以二进制模式读取文件并处理bytes以返回该模式。

您可以通过访问.buffer属性将STDIO流视为二进制流:

bytes_from_stdin = sys.stdin.buffer.read()
sys.stdout.buffer.write(bytes_to_stdout)

'b'添加到文件模式,以二进制模式打开文件。

通常,为STDIO编码/解码选择的编解码器基于运行脚本的终端的当前区域设置。要切换编解码器,您可以在终端中切换区域设置,或者通过设置PYTHONIOENCODING环境变量为Python设置一个区域设置

PYTHONIOENCODING=latin1 ./yourscript.py

文本文件应始终使用显式编解码器打开;不要依赖系统默认值。不过,我不确定修补open()是否是实现这一目标的最佳途径。

TextIOWrapper()的缓冲问题可以通过启用行缓冲来解决;如果设置line_buffering=True:,则每次向包装器写入n换行符时都会执行隐式buffer.flush()调用

sys.stdout = io.TextIOWrapper(
    sys.stdout.buffer, encoding="latin-1", line_buffering=True)

最新更新