Python 中通过 sys.stdout 输出 Unicode 字符串的方法

19
假设暂时不能使用`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已连接到终端)。

这是在sys.stdout中编写Unicode字符串的正确方法吗?还是我应该做些其他事情?

编辑:有时,例如将输出导出到less时,sys.stdout.encoding将为None。在这种情况下,上述代码将失败。


为了保持一致,将 s/my/ 替换为 one's. - icedwater
5个回答

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)

10

最好的方法是检查您是否直接连接到终端。如果是,则使用终端的编码方式。否则,请使用系统首选编码。

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

始终允许用户指定所需的编码非常重要。通常我会将其作为命令行选项(如-e ENCODING)并使用optparse模块解析它。

另一个好处是不要自动编码覆盖sys.stdout。创建您的编码器并使用它,但保留sys.stdout。您可以导入直接将已编码字节串写入sys.stdout的第三方库。


9

有一个可选的环境变量"PYTHONIOENCODING",可以设置为所需的默认编码。这是一种以与Python一致的方式获取用户所需编码的方法之一。它被埋藏在Python手册中这里


7

以下是我在我的应用程序中做的事情:

sys.stdout.write(s.encode('utf-8'))

这是从argv读取UTF-8名称的相反修复方法:

for file in sys.argv[1:]:
    file = file.decode('utf-8')

在我看来,这个做法很丑陋,因为它强制你使用UTF-8编码。虽然在Linux/Mac系统上使用UTF-8编码很常见,但在Windows系统上却不是。不过,这对我来说还是可行的 :)


3

我不太清楚为什么您不能进行打印操作,但是假设不能,那么这种方法对我来说看起来是正确的。


1
我不能使用 print 的一个原因是为了避免 print 打印的额外空格。请看这里对 sys.stdout 的使用:https://dev59.com/0EfYs4cB2Jgan1znIvNr#1397382 - Sridhar Ratnakumar
3
你可以先构建完整的行,然后再打印出来。 - Martin v. Löwis
1
添加逗号不会打印新行,但会打印额外的空格。尝试运行:python -c "print 2,; print 3," - Sridhar Ratnakumar
5
如果输出到管道中,程序不可能知道要使用哪种编码方式(因为它无法知道管道的另一端是less(1))。因此,你的应用程序必须自行确定/决定要使用的编码方式。 - Martin v. Löwis
1
在Python 3中,您可以使用print(stuff, sep='', end='')来避免额外的空格。我怀疑编码问题也不存在。 - ilya n.
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接