10
21
2016
3

在 Python 里设置 stdout 的编码

本文来自依云's Blog,转载请注明。

有时候进程的运行环境里,locale 会被设置成只支持 ASCII 字符集的(比如 LANG=C)。这时候 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 sys
import 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 更靠谱……

Category: python | Tags: Python 中文支持 linux | Read Count: 10481
x u b o y i n g 说:
Mar 06, 2018 11:32:07 AM

这篇文章似乎能启发我的一个问题,但是好像还是没有解决
仙子有兴趣调查一下么

https://stackoverflow.com/questions/48960633/how-to-properly-print-wide-chars-in-cmd-exe-under-chcp-65001-using-python

Avatar_small
依云 说:
Mar 06, 2018 11:43:25 AM

在那个下评论了。

话说你 chcp 65001 干嘛。要好好显示文字就用 PyQt 吧。

x u b o y i n g 说:
Mar 06, 2018 12:43:57 PM

调试用的,源目数据都是utf8,没必要适配其他locale,也没必要引入qt这么heavy的组件
看来升级Win10就行了,过段时间就升级了。

win下也可以用个 warkaround,输出到系统调试端口
import ctypes

# output "logging" messages to DbgView via OutputDebugString (Windows only!)
OutputDebugString = ctypes.windll.kernel32.OutputDebugStringW

class DbgViewHandler(logging.Handler):
def emit(self, record):
OutputDebugString(self.format(record))


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

部分静态文件存储由又拍云存储提供。 | Theme: Aeros 2.0 by TheBuckmaker.com