在Python中通过sys.stdout写入unicode字符串

19 投票
5 回答
35815 浏览
提问于 2025-04-15 14:35

假设我们不能使用 print 这个函数(这样就无法享受自动识别编码的好处)。那么我们只能用 sys.stdout。不过,sys.stdout 这个东西很笨,它根本不处理任何合理的编码

接下来,有人去看了Python的维基页面 PrintFails,然后尝试运行以下代码:

$ python -c 'import sys, codecs, locale; print str(sys.stdout.encoding); \
  sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout);

但是这个在Mac上也不管用。想知道为什么的话:

>>> import locale
>>> locale.getpreferredencoding()
'mac-roman'
>>> sys.stdout.encoding
'UTF-8'

(UTF-8是你的终端能理解的编码格式)。

于是,大家把上面的代码改成了:

$ python -c 'import sys, codecs, locale; print str(sys.stdout.encoding); \
  sys.stdout = codecs.getwriter(sys.stdout.encoding)(sys.stdout);

这样一来,unicode字符串就能正确地发送到 sys.stdout,并且在终端上正常显示了(因为 sys.stdout 是连接到终端的)。

这样写unicode字符串到 sys.stdout 是对的吗?还是说我应该做点别的?

编辑:有时候,比如在把输出传给 less 的时候,sys.stdout.encoding 可能会是 None。在这种情况下,上面的代码就会失败。

5 个回答

10

最好的办法是先检查一下你是否直接连接到了终端。如果是的话,就使用终端的编码方式。如果不是,那就用系统推荐的编码方式。

if sys.stdout.isatty():
    default_encoding = sys.stdout.encoding
else:
    default_encoding = locale.getpreferredencoding()

另外,允许用户自己选择想要的编码方式也是非常重要的。通常我会把这个选项放在命令行里(比如 -e ENCODING),然后用 optparse 模块来解析这个选项。

还有一点很重要,就是不要用自动编码器去覆盖 sys.stdout。你可以自己创建一个编码器并使用它,但要保持 sys.stdout 不变。你也可以导入一些第三方库,它们可以直接将编码后的字节字符串写入 sys.stdout

34
export PYTHONIOENCODING=utf-8

这个方法可以解决问题,但不能直接在Python里设置...

我们可以做的是检查一下是否没有设置,然后告诉用户在调用脚本之前要先设置它,方法是:

if __name__ == '__main__':
    if (sys.stdout.encoding is None):
        print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
        exit(1)
3

我不太明白你为什么不能使用打印功能;不过如果真是这样的话,我觉得你的做法是对的。

撰写回答