问题
源代码文件(test.py
)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
print u'中国'
执行
python test.py > output
输出
Traceback (most recent call last):
File "test.py", line 4, in <module>
print u'中国'
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
分析
可能 Python 是按照系统输出编码来输出。
实验 1
源代码文件(test_encoding.py
)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
print sys.getfilesystemencoding()
print sys.getdefaultencoding()
print sys.stdin.encoding
print sys.stdout.encoding
执行结果
1、直接执行
python test_encoding.py
# UTF-8
# ascii
# UTF-8
# UTF-8
2、直接执行,输出重定向
python test_encoding.py > output; cat output;
# UTF-8
# ascii
# UTF-8
# None
3、按指定本地化(locale)设置执行
查到一篇文档(Overcoming frustration: Correctly using unicode in python2)之后,又学到下面的调用姿势:
LC_ALL=C python test_encoding.py
# ANSI_X3.4-1968
# ascii
# ANSI_X3.4-1968
# ANSI_X3.4-1968
PS:LC_ALL=C python test.py
也会有 UnicodeEncodeError
。
猜测
是否是这样:如果没有指定标准输出的编码,就使用 sys.getdefaultencoding()
,结果导致 ASCII 编码 Unicode 字符出错。
所以继续实验,验证猜测。
实验 2
源代码文件(test2.py
)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u'中国'
执行结果
1、直接执行
python test2.py
# 中国
2、直接执行,输出重定向
python test2.py > output; cat output;
# 中国
3、按指定本地化(locale)设置执行
LC_ALL=C python test2.py
# Traceback (most recent call last):
# File "test2.py", line 9, in <module>
# print u'中国'
# UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
基本验证了我的猜测,如果没有指定标准输出的编码,那么使用了默认编码 ASCII。
解决方法
1、定义默认编码
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
2、重新定义标准输出
import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
参考
- readthedocs,kitchen 1.2.1 documentation,Overcoming frustration: Correctly using unicode in python2