当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《在Python中管道stdout时设置正确的编码》经验,为你挑选了5个好方法。

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

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

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

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"åäö"

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



1> Craig McQuee..:

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

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

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

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

import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)


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

2> nosklo..:

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

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

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

另一个教学示例是一个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)

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


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

3> daveagp..:

您可能想尝试将环境变量"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))

给你

utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ? ?


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

4> Sérgio..:
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)

更新回复评论:管道到stdout时问题就存在了.我在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.py | 减

None



5> CLaFarge..:

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

这是我的修复:

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

希望这可以帮助!

推荐阅读
mobiledu2402851377
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有