标签:
Python开发中,有时候进程的运行环境里,locale 会被设置成只支持 ASCII 字符集的(比如)。这时候 Python 就会把标准输出和标准错误的编码给设置成 ascii,造成输出中文时报错。
一种解决办法是设置支持 UTF-8 的 locale,但是那需要在 Python 进程启动前设置。启动之后,初始化过了,再设置 locale也不会重新初始化那些对象。
另一种办法是往 sys.stdout.buffer 这种地方直接写 bytes。理论上完全没问题,但是写起程序来好累……
我就去找了一下怎么优雅地弄一个新的 sys.stdout 出来。Python 3 的 I/O 不再使用 C 标准库的 I/O 函数,而是直接使用OS 提供的接口。封装位于 io 这个模块里边,有带缓冲的,不带缓冲的,二进制的,文本的。
研究了一下文档可知,sys.stdout 是个 io.TextIOWrapper,有个 buffer 属性,里边是个 io.BufferedWriter。我们用它造一个新的 io.TextIOWrapper,指定编码为 UTF-8:
import sysimport io
def setup_io():
sys.stdout = sys.__stdout__ = io.TextIOWrapper(
sys.stdout.detach(), encoding=’utf-8’, line_buffering=True)
sys.stderr = sys.__stderr__ = io.TextIOWrapper(
sys.stderr.detach(), encoding=’utf-8’, line_buffering=True)
这里除了可以设置编码之外,也可以设置错误处理和缓冲。所以这个技巧也可以用来容忍编码错误、改变标准输出的缓冲(不需要在启动的时候加 -u 了)。
其实这样子还是不够彻底。Python 在很多地方都有用到默认编码。比如 subprocess,指定 universal_newlines=True 时Python 会自动给标准输入、输出、错误编解码,但是呢,在 Python 3.6 之前,这里的编码是不能手动指定的。还有参数的编码,也是不能指定的(不过可以传 bytes 过去)。
所以,还是想办法去设置合适的 locale 更靠谱……
文章来源: 依云’s Blog
标签: