下面是一种更简单的方法(hack),可以让你重新获得从sys
中删除的setdefaultencoding()
函数:
import sys
# sys.setdefaultencoding() does not exist, here!
reload(sys) # Reload does the trick!
sys.setdefaultencoding('UTF8')
(针对Python 3.4+的注意事项:reload()
在 importlib
库中。)sys.setdefaultencoding()
被有意地从 sys
中删除。重新启用它并更改默认编码可能会破坏依赖ASCII作为默认编码的代码(这些代码可能是由第三方提供的,通常无法修复或危险)。LC_CTYPE
(或在应用程序中检查是否设置正确并使用有意义的错误消息终止)。 - ibottyLC_CTYPE=C python -c 'import locale; print( locale.getpreferredencoding())'
- ibottyPYTHONIOENCODING
,然后运行代码即可。export PYTHONIOENCODING=utf8
LC_CTYPE
设置为合适的值,这样做不仅可以使该程序更加稳定,还能让其他程序也变得更加顺畅。 - ibottyPYTHONIOENCODING=utf8
不是默认设置。这会导致脚本因为 LC_ALL=C
而崩溃。 - TinoA) 控制 sys.getdefaultencoding()
的输出:
python -c 'import sys; print(sys.getdefaultencoding())'
ASCII
然后
echo "import sys; sys.setdefaultencoding('utf-16-be')" > sitecustomize.py
PYTHONPATH=".:$PYTHONPATH" python -c 'import sys; print(sys.getdefaultencoding())'
utf-16-be
utf-16-be
是一种Unicode编码方式,它使用big-endian字节序来表示字符。
你可以将你的sitecustomize.py放在PYTHONPATH
更高的位置。
此外,您也可以尝试@EOL提供的reload(sys).setdefaultencoding
。
B) 要控制stdin.encoding
和stdout.encoding
,您需要设置PYTHONIOENCODING
:
python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'
ASCII ASCII
然后
PYTHONIOENCODING="utf-16-be" python -c 'import sys;
print(sys.stdin.encoding, sys.stdout.encoding)'
utf-16-be utf-16-be
Finally: 最后,你可以选择使用A或B或同时使用。
从PyDev 3.4.1开始,不再更改默认编码。 有关详细信息,请参见此票证。
对于早期版本,解决方案是确保PyDev不以UTF-8作为默认编码运行。在Eclipse下,运行对话框设置(如果我记得正确的话就是“运行配置”);您可以在常规选项卡上选择默认编码。如果要在PyDev环境中尽早发现这些错误,请将其更改为US-ASCII。还请参见此解决方法的原始博客文章。
关于Python2(仅限Python2),一些之前的答案依赖于使用以下技巧:
import sys
reload(sys) # Reload is a hack
sys.setdefaultencoding('UTF8')
使用sys.setdefaultencoding()是不被建议的(请参考此链接或此链接)。
在我的情况下,这样做会带来一个副作用:我正在使用ipython笔记本,在运行代码后,“print”函数将不再起作用。我想可能会有解决办法,但我仍然认为使用这个技巧不应该是正确的选项。
尝试了许多选项后,对我有效的是在sitecustomize.py
中使用相同的代码,因为那段代码的目的就是如此。在评估了该模块之后,将从sys中删除setdefaultencoding函数。
因此,解决方案是将代码附加到文件/usr/lib/python2.7/sitecustomize.py
:
import sys
sys.setdefaultencoding('UTF8')
当我使用virtualenvwrapper时,我编辑的文件是~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py
。
而当我使用python notebooks和conda时,它是~/anaconda2/lib/python2.7/sitecustomize.py
True
。u'Toshio' == 'Toshio'
sys.getdefaultencoding()
编码为ascii
的每个(正常的,未加前缀的)字符串,但对其他字符串则不适用。默认编码应在 site.py
中全局更改,而不是在其他地方更改。将其设置为用户模块中的类似技巧只是一种临时解决方案,而不是根本解决方案。Python 3已将系统编码更改为默认为utf-8(当LC_CTYPE支持Unicode时),但必须明确将“字节”字符串编码为Unicode字符串后,才能使用它们。sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')
首先,reload(sys)
并仅考虑输出终端流的随意设置一些默认编码是不好的做法。 reload
经常会更改依赖于环境的 sys.stdin/stdout 流、sys.excepthook 等在内的 sys 中的内容。
我所知道的解决在 sys.stdout 上打印 unicode 字符串和超出 ASCII 范围的 str
(例如从字面上)的编码问题的最佳方法是:关注一个能够满足需要且可选地容忍的 sys.stdout(类似文件对象):
当某种原因导致 sys.stdout.encoding
为 None
,或不存在,或错误地为 false 或比 stdout 终端或流实际能力“少”时,则尝试提供正确的 .encoding
属性。最后通过替换 sys.stdout & sys.stderr
来实现翻译文件对象。
当终端/流仍无法对所有出现的 unicode 字符进行编码,并且您不希望仅因此而破坏 print
,则可以在翻译文件对象中引入替换编码行为。
以下是一个示例:
#!/usr/bin/env python
# encoding: utf-8
import sys
class SmartStdout:
def __init__(self, encoding=None, org_stdout=None):
if org_stdout is None:
org_stdout = getattr(sys.stdout, 'org_stdout', sys.stdout)
self.org_stdout = org_stdout
self.encoding = encoding or \
getattr(org_stdout, 'encoding', None) or 'utf-8'
def write(self, s):
self.org_stdout.write(s.encode(self.encoding, 'backslashreplace'))
def __getattr__(self, name):
return getattr(self.org_stdout, name)
if __name__ == '__main__':
if sys.stdout.isatty():
sys.stdout = sys.stderr = SmartStdout()
us = u'aouäöüфżß²'
print us
sys.stdout.flush()
我认为唯一一个改变全局默认编码(仅限于UTF-8)的好理由是出于应用程序源代码决策,而不是因为I/O流编码问题:为了将超出ASCII的字符串字面值写入代码,而不必强制使用u'string'
样式的Unicode转义。这可以通过处理Python 2或Python 2+3源代码基础来实现一致性(尽管anonbadger的文章所说的不同),该基础使用ASCII或UTF-8纯字符串字面值 - 只要这些字符串可能会经历静默的Unicode转换并在模块之间移动或潜在地进入stdout。为此,请优先选择"# encoding: utf-8
"或ASCII(无声明)。更改或删除那些仍然以非常愚蠢的方式致命地依赖ASCII默认编码错误的库,超出了chr #127(这在今天很少见)。
并且在应用程序启动时(和/或通过sitecustomize.py)执行以下操作,除了上述的SmartStdout
方案 - 不使用reload(sys)
:
...
def set_defaultencoding_globally(encoding='utf-8'):
assert sys.getdefaultencoding() in ('ascii', 'mbcs', encoding)
import imp
_sys_org = imp.load_dynamic('_sys_org', 'sys')
_sys_org.setdefaultencoding(encoding)
if __name__ == '__main__':
sys.stdout = sys.stderr = SmartStdout()
set_defaultencoding_globally('utf-8')
s = 'aouäöüфżß²'
print s
这样,字符串字面量和大多数操作(除了字符迭代)在不考虑Unicode转换的情况下就可以轻松使用,就好像只存在Python3一样。
当然,与Python3一样,文件I/O始终需要特别注意编码。
注意:普通字符串在SmartStdout
中被隐式地从utf-8转换为Unicode,然后再转换为输出流编码。
# Encoding for file names
filesystemencoding = sys.getfilesystemencoding()
encoding = "ascii"
if sys.platform == 'win32':
# On Windows, we could use "mbcs". However, to give the user
# a portable encoding name, we need to find the code page
try:
# --> 6/5/17 hack to force IDLE to display utf-8 rather than cp1252
# --> encoding = locale.getdefaultlocale()[1]
encoding = 'utf-8'
codecs.lookup(encoding)
except LookupError:
pass
设置 Windows 环境变量 PYTHONUTF8=1