在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()函数,但更重要的是:它默认将所有字符串作为Unicode内部存储。例如,我有许多Latin-1 / ISO-8859-1编码的数据。
text = b'Eisb\xe4r'
为了按照既定方式处理它,我需要先将其解码为Unicode,这就是要做的事情。
text = text.decode('latin-1')
这是关于IT技术的内容。由于我系统上的默认编码是UTF-8,所以每当我打印一个字符串时,Python都会将内部的Unicode字符串编码为UTF-8。但首先它必须在内部完全是Unicode。
总的来说,这一切都很好运作,只是到目前为止还不能使用零字节输出缓冲区。有什么想法吗?我注意到在零缓冲行后sys.stdout.encoding未设置,但我不知道如何再次设置它。它是只读属性,操作系统环境变量LC_ALL或LC_CTYPE似乎只在Python解释器启动时进行评估。
顺便说一下:“Eisbär”是德语中“北极熊”的意思。
flag
引起版主的注意并告诉我们您需要什么! :) - slhckalias python="python -u"
,不要修改sys.stdout。顺便说一句,codecs.getwriter...仅在您(以及您使用的所有库)仅打印Unicode文本时才有效(因此通常不建议使用)。 - jfs