当输送Python程序的输出时,Python解释器会混淆编码并将其设置为None。这意味着这样一个程序:

# -*- coding: utf-8 -*-
print u"åäö"

正常运行时工作正常,但失败:

unicode编码错误:'ascii'编解码器无法编码字符u'\xa0'在位置0:序数不在范围(128)

在管道序列中使用时。

什么是最好的方法使这工作时管道?我能告诉它使用shell/文件系统/任何正在使用的编码吗?

到目前为止,我看到的建议是直接修改你的site.py,或者使用以下方法硬编码defaultencoding:

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u"åäö"

有没有更好的方法让管道工作?


当前回答

您的代码在脚本中运行时可以工作,因为Python将输出编码为终端应用程序使用的任何编码。如果你是管道,你必须自己编码。

一条经验法则是:始终在内部使用Unicode。解码你收到的,编码你发送的。

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

另一个有教育意义的例子是一个在ISO-8859-1和UTF-8之间转换的Python程序,在两者之间使用大写字母。

import sys
for line in sys.stdin:
    # Decode what you receive:
    line = line.decode('iso8859-1')

    # Work with Unicode internally:
    line = line.upper()

    # Encode what you send:
    line = line.encode('utf-8')
    sys.stdout.write(line)

设置系统默认编码是一个坏主意,因为您使用的一些模块和库可能依赖于它是ASCII的事实。不要这样做。

其他回答

我可以通过调用来“自动化”它:

def __fix_io_encoding(last_resort_default='UTF-8'):
  import sys
  if [x for x in (sys.stdin,sys.stdout,sys.stderr) if x.encoding is None] :
      import os
      defEnc = None
      if defEnc is None :
        try:
          import locale
          defEnc = locale.getpreferredencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.getfilesystemencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.stdin.encoding
        except: pass
      if defEnc is None :
        defEnc = last_resort_default
      os.environ['PYTHONIOENCODING'] = os.environ.get("PYTHONIOENCODING",defEnc)
      os.execvpe(sys.argv[0],sys.argv,os.environ)
__fix_io_encoding() ; del __fix_io_encoding

是的,如果这个“setenv”失败了,就有可能得到一个无限循环。

在Windows上,当我从编辑器(如Sublime Text)运行Python代码时经常遇到这个问题,但如果从命令行运行就不会。

在这种情况下,检查编辑器的参数。在SublimeText的情况下,这个Python。Sublime-build解决了这个问题:

{
  "cmd": ["python", "-u", "$file"],
  "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
  "selector": "source.python",
  "encoding": "utf8",
  "env": {"PYTHONIOENCODING": "utf-8", "LANG": "en_US.UTF-8"}
}

我很惊讶这个答案还没有被贴在这里

从Python 3.7开始,你可以用reconfigure()改变标准流的编码: sys.stdout.reconfigure(编码=“utf - 8”) 还可以通过添加errors参数来修改处理编码错误的方式。

https://stackoverflow.com/a/52372390/15675011

export PYTHONIOENCODING=utf-8

完成工作,但不能设置在python本身…

我们能做的是验证是否没有设置,并告诉用户在调用脚本之前设置它:

if __name__ == '__main__':
    if (sys.stdout.encoding is None):
        print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
        exit(1)

更新以回复评论: 问题只存在于管道到标准输出时。 我在Fedora 25 Python 2.7.13中测试

python --version
Python 2.7.13

猫b.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys

print sys.stdout.encoding

运行。/ b.py

UTF-8

运行。/b.p y| less

None

您的代码在脚本中运行时可以工作,因为Python将输出编码为终端应用程序使用的任何编码。如果你是管道,你必须自己编码。

一条经验法则是:始终在内部使用Unicode。解码你收到的,编码你发送的。

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

另一个有教育意义的例子是一个在ISO-8859-1和UTF-8之间转换的Python程序,在两者之间使用大写字母。

import sys
for line in sys.stdin:
    # Decode what you receive:
    line = line.decode('iso8859-1')

    # Work with Unicode internally:
    line = line.upper()

    # Encode what you send:
    line = line.encode('utf-8')
    sys.stdout.write(line)

设置系统默认编码是一个坏主意,因为您使用的一些模块和库可能依赖于它是ASCII的事实。不要这样做。