在Python中管道stdout时设置正确的编码

Joa*_*org 327 python terminal encoding stdout python-2.x

管道Python程序的输出时,Python解释器会对编码感到困惑,并将其设置为None.这意味着这样的程序:

# -*- coding: utf-8 -*-
print u"åäö"
Run Code Online (Sandbox Code Playgroud)

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

UnicodeEncodeError:'ascii'编解码器无法对位置0中的字符u'\ xa0'进行编码:序数不在范围内(128)

当在管道序列中使用时.

在配管时使这项工作的最佳方法是什么?我可以告诉它使用shell/filesystem /无论使用什么编码吗?

到目前为止我看到的建议是直接修改你的site.py,或者使用这个hack对defaultencoding进行硬编码:

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

是否有更好的方法使管道工作?

Cra*_*een 167

首先,关于这个解决方案:

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')
Run Code Online (Sandbox Code Playgroud)

每次使用给定的编码明确打印是不切实际的.这将是重复且容易出错的.

更好的解决方案是sys.stdout在程序开始时更改,使用选定的编码进行编码.这是我在Python上找到的一个解决方案:如何选择sys.stdout.encoding?,特别是"toka"的评论:

import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
Run Code Online (Sandbox Code Playgroud)

  • 我假设这个答案是针对python2的.**在代码上要小心,以支持python2和python3**.对我来说,在python3下运行时它会破坏它们. (8认同)
  • 不幸的是,将sys.stdout更改为仅接受unicode会破坏许多期望它接受编码字节串的库. (7认同)
  • nosklo:那么当输出是一个终端时,它如何可靠,自动地工作? (6认同)
  • @Rasmus Kaj:只需定义自己的unicode打印功能,并在每次打印unicode时使用它:`def myprint(unicodeobj):print unicodeobj.encode('utf-8')` - 通过检查自动检测终端编码`sys.stdout.encoding`,但你应该考虑它是`None`的情况(即将输出重定向到文件时),所以你需要一个单独的函数. (3认同)
  • @nosklo:这不会使sys.stdout只接受Unicode.您可以将str和unicode传递给StreamWriter. (3认同)

nos*_*klo 157

您的代码在脚本中运行时有效,因为Python会将输出编码为终端应用程序正在使用的任何编码.如果你是管道,你必须自己编码.

经验法则是:始终在内部使用Unicode.解码您收到的内容,并对您发送的内容进行编码.

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')
Run Code Online (Sandbox Code Playgroud)

另一个教学示例是一个Python程序,用于在ISO-8859-1和UTF-8之间进行转换,使得所有内容都处于大写状态.

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)
Run Code Online (Sandbox Code Playgroud)

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

  • 这个答案是对的.您应该*不*手动转换程序的每个输入和输出; 这很脆弱,完全无法维护. (62认同)
  • @Glenn Maynard:那么IYO的正确答案是什么?告诉我们比告诉我们更有帮助*'这个答案是错的'* (28认同)
  • @smci:答案是不要修改你的脚本,如果要在Python 2中重定向脚本的标准输出,请设置`PYTHONIOENCODING`. (13认同)
  • 问题是用户不想明确指定编码.他只想将Unicode用于IO.他使用的编码应该是区域设置中指定的编码,而不是终端应用程序设置中的编码.在这种情况下,AFAIK,Python 3使用*locale*编码.改变`sys.stdout`似乎是一种更愉快的方式. (11认同)
  • 当编码或解码调用丢失或在某处添加一次时,对每个字符串进行编码/解码必然会导致错误.当输出是终端时,可以设置输出编码,因此当输出不是终端时可以设置输出编码.甚至还有一个标准的LC_CTYPE环境来指定它.这是一个但在python中它不尊重这一点. (4认同)
  • @ErikJohansson:它不是关于stdout接受任何编码.`sys.getdefaultencoding()`用于很多地方,例如``а"+ u"a"`表达式使用它.更改`sys.getdefaultencoding()`可能会引入数据相关的错误,这些错误可能会以静默方式破坏您的数据. (4认同)
  • @Glenn Maynard实际上解码和编码是一个很好的做法,来自[python doc](https://docs.python.org/3/howto/unicode.html):"软件应该只在内部使用Unicode字符串,解码尽快输入数据并仅在结尾处对输出进行编码." (3认同)
  • 哪些库依赖stdout只接受ASCII?考虑到不是7位ASCII的数据量似乎是一个非常糟糕的主意. (2认同)

dav*_*agp 125

您可能想尝试将环境变量"PYTHONIOENCODING"更改为"utf_8".我已经在这个问题上写了一篇关于我的考验页面.

Tl;博客博士:

import sys, locale, os
print(sys.stdout.encoding)
print(sys.stdout.isatty())
print(locale.getpreferredencoding())
print(sys.getfilesystemencoding())
print(os.environ["PYTHONIOENCODING"])
print(chr(246), chr(9786), chr(9787))
Run Code Online (Sandbox Code Playgroud)

给你

utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ? ?
Run Code Online (Sandbox Code Playgroud)

  • @ jeckyll2hide:`PYTHONIOENCODING`确实有效.如何将字节解释为文本由*user*environment定义.您的脚本不应该假设并指示用户环境使用哪种字符编码.如果Python没有自动获取设置,则可以为脚本设置"PYTHONIOENCODING".除非将输出重定向到文件/管道,否则不应该需要它. (7认同)
  • +1.老实说,我认为这是一个Python错误.当我重定向输出时,我想要那些在终端上但在文件中的相同字节.也许它并不适合所有人,但它是一个很好的默认值.对于通常"正常工作"的微不足道的操作没有任何解释而严重崩溃是一个不好的默认值. (7认同)
  • 谢谢.现在,这从用户的角度来解决. (4认同)
  • 更改sys.stdout.encoding可能不起作用,但更改sys.stdout确实有效:`sys.stdout = codecs.getwriter(encoding)(sys.stdout)`.这可以在python程序中完成,因此用户不必强制设置env变量. (2认同)
  • @daveagp我的观点是,我的程序的行为不应该取决于它是否被重定向 - 除非我真的想要它,在这种情况下我自己实现它.Python的行为与我使用任何其他控制台工具的经验相反.这违反了最少的意外原则.我认为这是一个设计缺陷,除非有一个非常强大的理由. (2认同)

Sér*_*gio 61

export PYTHONIOENCODING=utf-8
Run Code Online (Sandbox Code Playgroud)

做的工作,但不能在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)
Run Code Online (Sandbox Code Playgroud)

更新回复评论:管道到stdout时问题就存在了.我在Fedora 25 Python 2.7.13中测试过

python --version
Python 2.7.13
Run Code Online (Sandbox Code Playgroud)

猫b.py

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

print sys.stdout.encoding
Run Code Online (Sandbox Code Playgroud)

正在运行./b.py

UTF-8
Run Code Online (Sandbox Code Playgroud)

正在运行./b.py | 减

None
Run Code Online (Sandbox Code Playgroud)

  • 该检查在 Python 2.7.13 中不起作用。`sys.stdout.encoding` 是根据 `LC_CTYPE` 语言环境值自动设置的。 (2认同)

qz-*_*qz- 8

我很惊讶这个答案还没有发布在这里

从 Python 3.7 开始,您可以使用以下命令更改标准流的编码reconfigure()

sys.stdout.reconfigure(encoding='utf-8')
Run Code Online (Sandbox Code Playgroud)

您还可以通过添加参数来修改处理编码错误的方式errors

/sf/answers/3666067331/


jac*_*ouh 7

从Python 3.7开始,我们可以通过使用命令行选项-X utf8来使用Python UTF-8模式:

\n
 python -X utf8 testzh.py\n
Run Code Online (Sandbox Code Playgroud)\n

脚本 testzh.py 包含

\n
print("Content-type: text/html; charset=UTF-8\\n") \nprint("\xe5\x9c\xb0\xe7\x90\x83\xe4\xbd\xa0\xe5\xa5\xbd!")\n\n
Run Code Online (Sandbox Code Playgroud)\n

要将 Windows 10 Internet 服务 IIS 设置为 CGI 脚本处理程序,

\n

我们将可执行文件设置为:

\n
"C:\\Program Files\\Python39\\python.exe" -X utf8 %s\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

这适用于 Microsoft.Edge 浏览器上的中文表意文字,如下截图所示: 否则,会发生错误。

\n

在此输入图像描述

\n

请参阅https://docs.python.org/3/library/os.html#utf8-mode

\n


CLa*_*rge 5

上周我有类似的问题.在我的IDE(PyCharm)中很容易修复.

这是我的修复:

从PyCharm菜单栏开始:File - > Settings ... - > Editor - > File Encodings,然后设置:"IDE Encoding","Project Encoding"和"属性文件的默认编码"ALL到UTF-8,她现在正在工作喜欢魅力.

希望这可以帮助!