对于脚本,是否将python3默认为latin-1?

对于脚本,是否将python3默认为latin-1?,python,python-3.x,encoding,Python,Python 3.x,Encoding,TL;DR:我可以让Python 3使用unicode以外的任何东西作为默认编码吗 我有一些用Python 3编写的脚本。在对我自己的文件进行操作时,它们工作得很好,因为文件以utf-8编码,并且通常只使用ASCII兼容子集 现在我试着在几十年前的源文件上使用相同的脚本,结果发现unicode异常到处都是。完全有可能的是,这些文件是由编辑器在一年中采用不同的编码进行编辑的,因此每个文件的编码可能不同,甚至定义不清 如果我用Python2编写脚本,它假定使用固定宽度编码,那么一切都会正常工作。使用

TL;DR:我可以让Python 3使用unicode以外的任何东西作为默认编码吗

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

现在我试着在几十年前的源文件上使用相同的脚本,结果发现unicode异常到处都是。完全有可能的是,这些文件是由编辑器在一年中采用不同的编码进行编辑的,因此每个文件的编码可能不同,甚至定义不清

如果我用Python2编写脚本,它假定使用固定宽度编码,那么一切都会正常工作。使用非ascii字符的部分仅在注释中

在Python3中,当编码未知且可能定义不清时,干净的解决方案是只对字节数组数据进行操作,但是缺少
.format
函数,以及需要在任何地方区分字节和str文本,这既是一个语法噩梦,也是一个耗时的问题,不值得在我的脚本中进行修复

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

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

我能想到的最好的依据是

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

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

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

bytes_from_stdin = sys.stdin.buffer.read()
sys.stdout.buffer.write(bytes_to_stdout)
'b'
添加到文件模式,以二进制模式打开文件

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

PYTHONIOENCODING=latin1 ./yourscript.py
文本文件应始终使用显式编解码器打开;不要依赖系统默认设置。不过,我不确定修补
open()
是否是最好的方法

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

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

为什么您认为这会导致严重的缓冲?您没有添加任何缓冲,而是删除了文本I/O包装,用另一个包装替换它。这不会改变缓冲行为,所以我会这么想。但在添加行之前,脚本将在运行时生成输出。在添加行之后,在处理完成后,输出将成为一个整体。显然,新的TextIOWrapper添加了缓冲。唯一的缓冲选项
TextIOWrapper()
line\u buffering
参数。将其设置为
True
以在写入换行时向基础缓冲区发送隐式
flush()
。谢谢,该参数部分解决了问题(因为不仅
“\n”
而且
“\r”
似乎会导致刷新,这是某些状态消息所必需的)。您可以将此更改转化为我可以接受的答案(通过此更改,它满足了我的要求)。您可以始终向
print()
语句添加
flush=True
参数。遗憾的是,使用基于字节的API会导致代码冗长(直到python 3.4,至少没有
bytes.format
)和大量重构(将字符串文字替换为字节文字,但注意不要替换字节无效的文字)。这可能是一个干净的解决方案,但对于一组shell脚本来说是不可行的。使用PYTHONIOENCODING是可行的,但需要包装脚本,或者如果设置为全局值,则会引入模糊的依赖于机器的行为。至于修补
open()
,该解决方案旨在避免重构受影响的脚本。@kdb:您的意思是将其标记为已接受,然后再次标记为不接受吗?这里有什么我可以帮忙的吗?
sys.stdout = io.TextIOWrapper(
    sys.stdout.buffer, encoding="latin-1", line_buffering=True)