Unicode Python3使用sys.stdout.buffer.write()的风格好吗?

Unicode Python3使用sys.stdout.buffer.write()的风格好吗?,unicode,cgi,python-3.x,Unicode,Cgi,Python 3.x,在我学习了Python3.0Web脚本中的unicode文件之后,现在是时候学习如何将print()与unicode结合使用了 我搜索了编写unicode,例如,解释了不能将unicode字符写入非unicode控制台。然而,在我的例子中,输出被提供给Apache,我确信它能够处理unicode文本。但是,出于某种原因,我的web脚本的标准输出是在ascii中的 显然,如果我打开一个文件来写自己,我会做如下的事情 open(filename, 'w', encoding='utf8') 但由于

在我学习了Python3.0Web脚本中的unicode文件之后,现在是时候学习如何将
print()
与unicode结合使用了

我搜索了编写unicode,例如,解释了不能将unicode字符写入非unicode控制台。然而,在我的例子中,输出被提供给Apache,我确信它能够处理unicode文本。但是,出于某种原因,我的web脚本的标准输出是在ascii中的

显然,如果我打开一个文件来写自己,我会做如下的事情

open(filename, 'w', encoding='utf8')
但由于我得到了一条开放的溪流,我求助于使用

sys.stdout.buffer.write(mytext.encode('utf-8'))

一切似乎都正常。这是否违反了良好行为准则,或者有任何意外后果

我认为你没有违反任何规则,但是

sys.stdout = codecs.EncodedFile(sys.stdout, 'utf8')
看起来它可能更轻便/不那么笨重

编辑:根据评论,这不太正确--@Miles给出了正确的变体(谢谢!):


编辑:如果您可以在Apache启动脚本时将环境变量
PYTHONIOENCODING
设置为utf8,那会更好,使
sys.stdout
自动设置为
utf8
;但是,如果这不可行或不切实际,
编解码器解决方案仍然有效。

这是一个古老的答案,但我将在这里添加我的版本,因为我在找到解决方案之前第一次冒险来到这里

getwriter的一个问题是,如果运行某种脚本,输出将被缓冲(而python标准输出通常在每行之后打印)

控制台中的sys.stdout
是一个IOTextWrapper,所以我的解决方案使用它。这也允许您设置line_buffering=True或False

例如,要将标准输出设置为,而不是错误,请对所有输出进行反斜杠编码:

sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding=sys.stdout.encoding,
                              errors="backslashreplace", line_buffering=True)
要强制进行特定编码(在本例中为utf8),请执行以下操作:

注意,调用sys.stdout.detach()将关闭底层缓冲区。有些模块使用的是
sys.stdout\uuu
,这只是
sys.stdout
的别名,因此您可能也需要设置它

sys.stdout = sys.__stdout__ = io.TextIOWrapper(sys.stdout.detach(), encoding=sys.stdout.encoding, errors="backslashreplace", line_buffering=True)
sys.stderr = sys.__stderr__ = io.TextIOWrapper(sys.stderr.detach(), encoding=sys.stdout.encoding, errors="backslashreplace", line_buffering=True)

通过这一行,我得到了“TypeError:can't write bytes to text stream”,我想这是因为stdout已经开始成为一个带有错误ascii编解码器的文本流了。试试看:sys.stdout=codecs.getwriter('utf8')(sys.stdout.buffer)@Miles,你说得对——希望你不介意我编辑我的答案,把你更好的想法包括进去。。。!没问题。我没有给出自己的答案,因为我不确定对于许多Python3编码问题,什么是“最佳实践”。我不喜欢的一件事是,如果对原始stdout TextIOWrapper的所有引用都丢失(例如,如果sys.\uu stdout\uuuuuu被覆盖),底层缓冲区将被关闭,除了确保保留引用之外,没有其他方法可以解决这个问题。您可以编写当前系统不支持的Unicode字符(Windows)控制台编码如果您使用Win32 API,例如
WriteConsoleW()
。它会为您进行编码。虽然它与Apache无关。我在几个地方见过非常类似的解决方案,但我发现它有一个问题(Windows,python 3.6):如果您执行类似于“myprog.py | head”的操作,python会抛出一个奇怪的错误:“在中忽略异常:有趣…我可以在读取所有数据之前在cmd.exe和msys bash上假定关闭stdout时重现以下错误。在3.5和3.6上…回溯(最近一次调用):文件“crash_in_head.py”,第7行,打印('hi')OSError:[Errno 22]中忽略无效参数异常:OSError:[Errno 22]无效的论点你的建议确实解决了这个问题!
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding="utf8",
                              line_buffering=True)
sys.stdout = sys.__stdout__ = io.TextIOWrapper(sys.stdout.detach(), encoding=sys.stdout.encoding, errors="backslashreplace", line_buffering=True)
sys.stderr = sys.__stderr__ = io.TextIOWrapper(sys.stderr.detach(), encoding=sys.stdout.encoding, errors="backslashreplace", line_buffering=True)