归结为您的输出流编码。在这种特殊情况下,由于您使用的是print,因此使用的输出文件是sys.stdout。
交互模式/stdout 未重定向
当你以交互模式运行 Python 时,或者当你不将stdout 重定向到文件时,Python 使用基于环境的编码,即语言环境变量,如LC_CTYPE。例如,如果您像这样运行程序:
$ LC_CTYPE='en_US' python test.py
...
UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-4: ordinal not in range(128)
它将使用ANSI_X3.4-1968 代替sys.stdout(参见sys.stdout.encoding)并失败。但是,您是否使用UTF-8(显然您已经这样做了):
$ LC_CTYPE='en_US.UTF-8' python test.py
1234567890
abcd
αβγδ
你会得到预期的输出。
stdout 重定向到文件
当您将stdout 重定向到文件时,Python 不会尝试从您的环境语言环境中检测编码,但它会检查另一个环境变量PYTHONIOENCODING(检查源代码initstdio() in Python/pylifecycle.c)。例如,这将按预期工作:
$ PYTHONIOENCODING=utf-8 python test.py >/tmp/output
因为 Python 将对/tmp/output 文件使用UTF-8 编码。
手动stdout编码覆盖
您也可以使用所需的编码手动重新打开sys.stdout(检查this 和this SO 问题):
import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
现在print 将正确输出str 和unicode 对象,因为底层流编写器会将它们即时转换为UTF-8。
输出前手动编码字符串
当然,您也可以在输出之前手动将每个unicode 编码为UTF-8 str:
print ('%5s' % s2).encode('utf8')
但这很乏味且容易出错。
显式文件打开
为了完整性:在 Python 2 中打开文件以使用特定编码(如 UTF-8)进行写入时,您应该使用io.open 或codecs.open,因为它们允许您指定编码(请参阅this question) ,不像内置的open:
from codecs import open
myfile = open('filename', encoding='utf-8')
或:
from io import open
myfile = open('filename', encoding='utf-8')