在Python中通过sys.stdout写入unicode字符串
假设我们不能使用 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
我不太明白你为什么不能使用打印功能;不过如果真是这样的话,我觉得你的做法是对的。