当我在 Python 中编写 sysadmin 脚本时,影响每次调用 print() 的 sys.stdout 上的缓冲区很烦人,因为我不想等待缓冲区被刷新然后在一旦在屏幕上,我想在脚本生成新输出后立即获得单独的输出行。我什至不想等待换行符,所以请查看输出。
在 python 中执行此操作的常用习语是
import os
import sys
sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
这对我来说很长一段时间都很好。现在我注意到,它不适用于 Unicode。请参阅以下脚本:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import os
import sys
print('Original encoding: {}'.format(sys.stdout.encoding))
sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
print('New encoding: {}'.format(sys.stdout.encoding))
text = b'Eisb\xe4r'
print(type(text))
print(text)
text = text.decode('latin-1')
print(type(text))
print(text)
这导致以下输出:
Original encoding: UTF-8
New encoding: None
<type 'str'>
Eisb▒r
<type 'unicode'>
Traceback (most recent call last):
File "./export_debug.py", line 18, in <module>
print(text)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 4: ordinal not in range(128)
我花了几个小时才找到它的原因(我的原始脚本比这个最小的调试脚本长得多)。这是线
sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
我使用了多年,所以没想到会有任何问题。只需注释掉这一行,正确的输出应该如下所示:
Original encoding: UTF-8
New encoding: UTF-8
<type 'str'>
Eisb▒r
<type 'unicode'>
Eisbär
那么脚本要做什么呢?为了让我的 Python 2.7 代码尽可能接近 Python 3.x,我一直在使用
from __future__ import print_function, unicode_literals
这使得 python 使用新的 print() 函数,但更重要的是:它使 Python 默认在内部将所有字符串存储为 Unicode。例如,我有很多 Latin-1 / ISO-8859-1 编码数据
text = b'Eisb\xe4r'
要以预期的方式使用它,我需要先将其解码为 Unicode,这就是
text = text.decode('latin-1')
是为了。由于我系统上的默认编码是 UTF-8,每当我打印一个字符串时,python 都会将内部 Unicode 字符串编码为 UTF-8。但首先它必须在内部使用完美的 Unicode。
现在一切正常,只是到目前为止还没有零字节输出缓冲区。有任何想法吗?我注意到 sys.stdout.encoding 在零缓冲行之后未设置,但我不知道如何再次设置它。它是一个只读属性,OS 环境变量 LC_ALL 或 LC_CTYPE 似乎只在 python 解释器启动时才被评估。
顺便说一句:“Eisbär”是德语中“北极熊”的意思。