【问题标题】:Python 3, is using sys.stdout.buffer.write() good style?Python 3,使用 sys.stdout.buffer.write() 的风格好吗?
【发布时间】:2010-11-02 07:27:59
【问题描述】:

在我了解了 Python 3.0 Web 脚本中的 reading unicode 文件之后,现在是我学习将 print() 与 unicode 结合使用的时候了。

我搜索了写 unicode,例如 this question 解释说您不能将 unicode 字符写入非 unicode 控制台。但是,在我的例子中,输出是给 Apache 的,我确信它能够处理 unicode 文本。然而,出于某种原因,我的网络脚本的stdoutascii 中。

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

open(filename, 'w', encoding='utf8')

但由于我得到了一个开放的流,我求助于使用

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

一切似乎都正常。这是否违反了一些良好行为规则或有任何意想不到的后果?

【问题讨论】:

标签: unicode cgi python-3.x


【解决方案1】:

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

sys.stdout = codecs.EncodedFile(sys.stdout, 'utf8')

看起来它可能更方便/不那么笨重。

编辑:每个 cmets,这不太正确——@Miles 给出了正确的变体(谢谢!):

sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer) 

编辑:如果你可以安排环境变量PYTHONIOENCODING在Apache启动你的脚本时设置为utf8,那就更好了,让sys.stdout自动设置为utf8;但如果这不可行或不切实际,codecs 解决方案就成立了。

【讨论】:

  • 通过这一行,我得到“TypeError: can't write bytes to text stream”
  • 我认为这是因为 stdout 已经开始成为带有 错误 ascii 编解码器的文本流。
  • 试试:sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
  • @Miles,你说得对 - 希望你不介意我编辑我的答案以包含你更好的想法......!
  • 没问题。我没有做出自己的答案,因为我不确定对于许多 Python 3 编码问题来说什么是“最佳实践”。我不喜欢的一件事是,如果对原始标准输出 TextIOWrapper 的所有引用都丢失(例如,如果 sys.__stdout__ 被覆盖),则底层缓冲区将被关闭,并且没有办法解决这个问题,AFAICT,其他而不是确保参考得到维护。
【解决方案2】:

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

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

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

例如,将 stdout 设置为,而不是错误,反斜杠编码所有输出:

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

强制使用特定编码(在本例中为 utf8):

sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding="utf8",
                              line_buffering=True)

注意,调用 sys.stdout.detach() 将关闭底层缓冲区。一些模块使用sys.__stdout__,它只是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)

【讨论】:

  • 我在几个地方看到了非常相似的解决方案,但我发现它有一个问题(Windows,python 3.6):如果你执行“myprog.py | head”之类的操作,那么 python 会抛出一个奇怪的错误:“异常被忽略:
  • 有趣...当 stdout 在读取所有内容之前可能已关闭时,在 cmd.exe 和 msys bash 上,我可以重现以下错误。在 3.5 和 3.6... 回溯(最近一次调用最后一次):文件“crash_in_head.py”,第 7 行,在 print('hi') OSError: [Errno 22] Invalid argument Exception 在:<_io. textiowrapper name="<stdout>" encoding="utf8"> OSError: [Errno 22] Invalid argument 你的建议确实解决了这个问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 2010-11-25
  • 2016-03-04
  • 1970-01-01
  • 2010-10-31
  • 2020-10-19
相关资源
最近更新 更多