【问题标题】:Default encoding for python for stderr?标准错误的python的默认编码?
【发布时间】:2010-10-12 20:25:27
【问题描述】:

我有一个嘈杂的 Python 脚本,我想通过将其 stderr 输出定向到 /dev/null(使用 bash BTW)来使其静音。

像这样:

python -u parse.py  1> /tmp/output3.txt 2> /dev/null

但它很快就会过早退出。唔。我看不到回溯,因为标准错误当然会消失。如果我不将 stderr 引导到某个地方,它会正常运行且嘈杂。

所以让我们尝试将它重定向到某个文件而不是 /dev/null,然后看看它输出了什么:

python -u parse.py  1> /tmp/output3.txt 2> /tmp/foo || tail /tmp/foo

Traceback (most recent call last):
  File "parse.py", line 79, in <module>
    parseit('pages-articles.xml')
  File "parse.py", line 33, in parseit
    print >>sys.stderr, "bad page title", page_title
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

所以,正在生成的标准错误包含 utf8,并且由于某种原因,python 在重定向时拒绝打印非 ascii,即使它被定向到 /dev/null(当然 python 不知道) .

即使 python 脚本的标准错误包含 utf8,我如何才能使其静音?有什么方法可以做到这一点,而无需在此脚本中将每个打印内容都重写到 stderr?

【问题讨论】:

    标签: python bash shell unicode


    【解决方案1】:

    您可以通过将 stderr 绑定到自定义编写器来使其静音:

    #!/usr/bin/env python
    import codecs, sys
    
    class NullWriter:
        def write(self, *args, **kwargs):
            pass
    
    if len(sys.argv) == 2:
       if sys.argv[1] == '1':
          sys.stderr = NullWriter()
       elif sys.argv[1] == '2':
          #NOTE: sys.stderr.encoding is *read-only* 
          #      therefore the whole stderr should be replaced
          # encode all output using 'utf8'
          sys.stderr = codecs.getwriter('utf8')(sys.stderr)
    
    print >>sys.stderr, u"\u20AC" # euro sign
    print "ok"
    

    例子:

    $ python silence_stderr.py
    Traceback (most recent call last):
      File "silence_stderr.py", line 11, in <module>
        print >>sys.stderr, u"\u20AC"
    UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
    

    静音标准错误:

    $ python silence_stderr.py 1
    ok
    

    编码标准错误:

    $ python silence_stderr.py 2
    €
    ok
    

    注意:我在 emacs 中有上述输出,因此可以在终端中模拟它:

    $ python ... 2>out.txt
    $ cat out.txt
    

    注意:在 Windows 控制台内(chcp 65001 切换到 'utf-8' 并使用 truetype 字体 (Lucida Console))我得到了奇怪的结果:

    C:\> python silence_stderr.py 2
    Traceback (most recent call last):
      File "silence_stderr.py", line 14, in <module>
        print >>sys.stderr, u"\u20AC" # euro sign
      File "C:\pythonxy\python\lib\codecs.py", line 304, in write
        self.stream.write(data)
    IOError: [Errno 13] Permission denied
    

    如果字体不是 truetype,则不会引发异常,但输出错误。

    Perl 适用于 truetype 字体:

    C:\> perl  -E"say qq(\x{20ac})"
    Wide character in print at -e line 1.
    €
    

    虽然重定向有效:

    C:\>python silence_stderr.py 2 2>tmp.log
    ok
    C:\>cat tmp.log
    €
    cat: write error: Permission denied
    

    重新评论

    来自codecs.getwriter 文档:

    查找给定的编解码器 编码并返回其 StreamWriter 类或工厂函数。提出一个 LookupError 以防编码 找不到。

    过于简单的观点:

    class UTF8StreamWriter:
        def __init__(self, writer):
            self.writer = writer
        def write(self, s):
            self.writer.write(s.encode('utf-8'))
    
    sys.stderr = UTF8StreamWriter(sys.stderr)
    

    【讨论】:

    • 真的很酷...你能解释一下 codecs.getwriter 是做什么的吗?
    【解决方案2】:

    当 stderr 没有被重定向时,它会接受终端的编码。但是,当您重定向它时,这一切都会消失。您需要使用 sys.stderr.isatty() 来检测它是否被重定向并正确编码。

    【讨论】:

    • 实际上,sys.stderr.encoding 不是由终端的编码定义的,终端的编码可能会通过 python 未知的各种方式进行更改。 stderr.encoding 更有可能是由 LC_* 环境变量或类似变量定义的。
    • 嗯,终端的编码是由这些变量决定的,所以最终结果是一样的。
    • @Ignacio Vazquez-Abrams:问题很复杂,例如bugs.python.org/issue4947
    • LC_* 是一个环境变量。它可能由 xterm/etc 设置。但它不能确定 xterm/etc 的编码是什么。使用。
    • LC_* 由 shell 而非 xterm 设置,并确定编码(例如 xx_XX.UTF-8)
    【解决方案3】:

    您也可以将字符串编码为 ASCII,替换不映射的 unicode 字符。那你就不用担心你有什么样的终端了。

    asciiTitle = page_title.encode("ascii", "backslashreplace")
    print >>sys.stderr, "bad page title", asciiTitle
    

    这将替换无法用反斜杠转义编码的字符,即\xfc。还有一些其他替换选项,如下所述:

    http://docs.python.org/library/stdtypes.html#str.encode

    【讨论】:

    • 真的,如果没有办法强制文件句柄为 unicode,那么这个(反斜杠替换)应该是 stderr 的默认值!
    猜你喜欢
    • 1970-01-01
    • 2016-07-18
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多