首页 文章

如何在Python中打印到stderr?

提问于
浏览
1052

我有几种方法可以写入stderr:

# Note: this first one does not work in Python 3
 print >> sys.stderr, "spam"

 sys.stderr.write("spam\n")

 os.write(2, b"spam\n")

 from __future__ import print_function
 print("spam", file=sys.stderr)

它似乎与Python#13†的禅相矛盾,那么首选方法是什么?这种或那种方式有任何优点或缺点吗?

†应该有一个 - 最好只有一个 - 显而易见的方法 .

15 回答

  • 16

    这将模仿标准打印功能,但在stderr上输出

    def print_err(*args):
        sys.stderr.write(' '.join(map(str,args)) + '\n')
    
  • 107

    问题的答案是:在python中有不同的方法来打印stderr,但这取决于1.)我们使用的是哪个python版本2.)我们想要的确切输出 .

    print和stderr的写入函数之间的区别: stderr :stderr(标准错误)是内置于每个UNIX / Linux系统的管道,当程序崩溃并打印出调试信息(如Python中的回溯)时,它会转到stderr管 .

    print :print是一个包装器,用于格式化输入(输入是参数和结尾处的换行符之间的空格),然后它调用给定对象的write函数,默认情况下给定的对象是sys.stdout,但是我们可以传递文件,即我们也可以在文件中打印输入 .

    Python2:如果我们使用python2那么

    >>> import sys
    >>> print "hi"
    hi
    >>> print("hi")
    hi
    >>> print >> sys.stderr.write("hi")
    hi
    

    Python3中的Python2尾随逗号成为参数,因此如果我们使用尾随逗号来避免打印后的换行符,这将在Python3中看起来像print('Text to print',end ='')这是一个语法错误Python2 .

    http://python3porting.com/noconv.html

    如果我们在python3中检查上面的sceario:

    >>> import sys
    >>> print("hi")
    hi
    

    在Python 2.6下,将来可以将print打印到函数中 . 因此,为了避免任何语法错误和其他差异,我们应该从将来的import print_function开始使用print()的任何文件 . 未来的导入仅适用于Python 2.6及更高版本,因此对于Python 2.5及更早版本,您有两种选择 . 您可以将更复杂的打印转换为更简单的打印,也可以使用在Python2和Python3下都可以使用的单独打印功能 .

    >>> from __future__ import print_function
    >>> 
    >>> def printex(*args, **kwargs):
    ...     print(*args, file=sys.stderr, **kwargs)
    ... 
    >>> printex("hii")
    hii
    >>>
    

    案例:请注意,sys.stderr.write()或sys.stdout.write()(stdout(标准输出)是内置于每个UNIX / Linux系统的管道)不是打印的替代品,但是是的,我们可以在某些情况下将其用作替代品 . Print是一个包装器,它在最后用空格和换行包装输入,并使用write函数进行写入 . 这就是sys.stderr.write()更快的原因 . 注意:我们还可以使用Logging进行跟踪和调试

    #test.py
    import logging
    logging.info('This is the existing protocol.')
    FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s"
    logging.basicConfig(format=FORMAT)
    d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
    logging.warning("Protocol problem: %s", "connection reset", extra=d)
    

    https://docs.python.org/2/library/logging.html#logger-objects

  • 3

    对于 Python 2 ,我的选择是: print >> sys.stderr, 'spam' 因为你可以简单地打印列表/ dicts等而不将其转换为字符串 . print >> sys.stderr, {'spam': 'spam'} 而不是: sys.stderr.write(str({'spam': 'spam'}))

  • 431
    import sys
    sys.stderr.write()
    

    是我的选择,只是更具可读性,并准确说明您打算做什么,并且可以跨版本移植 .

    编辑:成为'pythonic'是第三个想到我的可读性和性能......考虑到这两个方面,python 80%的代码将是pythonic . 列表理解是不常用的“大事”(可读性) .

  • 4

    如果你做一个简单的测试:

    import time
    import sys
    
    def run1(runs):
        x = 0
        cur = time.time()
        while x < runs:
            x += 1
            print >> sys.stderr, 'X'
        elapsed = (time.time()-cur)
        return elapsed
    
    def run2(runs):
        x = 0
        cur = time.time()
        while x < runs:
            x += 1
            sys.stderr.write('X\n')
            sys.stderr.flush()
        elapsed = (time.time()-cur)
        return elapsed
    
    def compare(runs):
        sum1, sum2 = 0, 0
        x = 0
        while x < runs:
            x += 1
            sum1 += run1(runs)
            sum2 += run2(runs)
        return sum1, sum2
    
    if __name__ == '__main__':
        s1, s2 = compare(1000)
        print "Using (print >> sys.stderr, 'X'): %s" %(s1)
        print "Using (sys.stderr.write('X'),sys.stderr.flush()):%s" %(s2)
        print "Ratio: %f" %(float(s1) / float(s2))
    

    你会发现sys.stderr.write()的速度始终是 1.81 倍!

  • 127
    import logging
    logging.basicConfig(format='[%(levelname)s] %(message)s')
    
    logging.error('is error, alarm!')
    logging.warning('is simple waring')
    
    print('hello')
    

    pydoc日志记录

  • 28

    还没有人提到 logging ,但是专门为了传递错误消息而创建了日志记录 . 默认情况下,它设置为写入stderr . 这个脚本:

    # foo.py
    import logging
    logging.basicConfig(format='%(message)s')
    
    logging.warning('I print to stderr by default')
    logging.info('For this you must change the level and add a handler.')
    print('hello world')
    

    在命令行上运行时,结果如下:

    $ python3 foo.py > bar.txt
    I print to stderr by default
    

    (和bar.txt包含'hello world')

    (注意, logging.warndeprecated,请改用 logging.warning

  • 33

    我使用Python 3做了以下事情:

    from sys import stderr
    
    def print_err(*args, **kwargs):
        print(*args, file=stderr, **kwargs)
    

    所以现在我可以添加关键字参数,例如,以避免回车:

    print_err("Error: end of the file reached. The word ", end='')
    print_err(word, "was not found")
    
  • -1

    我在python 3.4.3中工作 . 我正在切出一个小小的打字,显示我是如何到达这里的:

    [18:19 jsilverman@JSILVERMAN-LT7 pexpect]$ python3
    >>> import sys
    >>> print("testing", file=sys.stderr)
    testing
    >>>
    [18:19 jsilverman@JSILVERMAN-LT7 pexpect]$
    

    它有用吗?尝试将stderr重定向到文件,看看会发生什么:

    [18:22 jsilverman@JSILVERMAN-LT7 pexpect]$ python3 2> /tmp/test.txt
    >>> import sys
    >>> print("testing", file=sys.stderr)
    >>> [18:22 jsilverman@JSILVERMAN-LT7 pexpect]$
    [18:22 jsilverman@JSILVERMAN-LT7 pexpect]$ cat /tmp/test.txt
    Python 3.4.3 (default, May  5 2015, 17:58:45)
    [GCC 4.9.2] on cygwin
    Type "help", "copyright", "credits" or "license" for more information.
    testing
    
    [18:22 jsilverman@JSILVERMAN-LT7 pexpect]$
    

    好吧,除了python给你的小介绍已经悄悄进入stderr(它还会去哪里?)之外,它有效 .

  • 904

    EDIT 在后视中,我认为改变sys.stderr并且没有看到行为更新的潜在混淆使得这个答案不如使用其他人指出的简单函数那么好 .

    使用partial只能为您节省1行代码 . 潜在的混淆不值得保存1行代码 .

    original

    为了使它更容易,这里是一个使用'partial'的版本,这对包装函数有很大帮助 .

    from __future__ import print_function
    import sys
    from functools import partial
    
    error = partial(print, file=sys.stderr)
    

    然后你就这样使用它

    error('An error occured!')
    

    您可以通过执行以下操作来检查它是否正在打印到stderr而不是stdout(从http://coreygoldberg.blogspot.com.au/2009/05/python-redirect-or-turn-off-stdout-and.html覆盖代码):

    # over-ride stderr to prove that this function works.
    class NullDevice():
        def write(self, s):
            pass
    sys.stderr = NullDevice()
    
    # we must import print error AFTER we've removed the null device because
    # it has been assigned and will not be re-evaluated.
    # assume error function is in print_error.py
    from print_error import error
    
    # no message should be printed
    error("You won't see this error!")
    

    这样做的缺点是sys.stderr在创建时对包装函数的值是部分 assigns . 这意味着, if you redirect stderr later it won't affect this function. 如果您计划重定向stderr,请使用此页面上aaguirre提到的** kwargs方法 .

  • 6

    这同样适用于stdout:

    print 'spam'
    sys.stdout.write('spam\n')
    

    正如其他答案所述,print提供了一个漂亮的界面,通常更方便(例如打印调试信息),当你必须以某种方式确切地格式化输出时,写入更快并且也更方便 . 我也会考虑可维护性:

    • 您稍后可能决定在stdout / stderr和常规文件之间切换 .

    399 print()语法在Python 3中已经改变,所以如果你需要支持这两个版本,write()可能会更好 .

  • 71

    print >> sys.stderr 在Python3中消失了 . http://docs.python.org/3.0/whatsnew/3.0.html说:

    Old: print >>sys.stderr, "fatal error"
    New: print("fatal error", file=sys.stderr)
    

    不幸的是,这非常难看 . 或者,使用

    sys.stderr.write("fatal error\n")
    

    但请注意 write 不是 print 的1:1替代品 .

  • 0

    我会说你的第一个方法:

    print >> sys.stderr, 'spam'
    

    是“一个...... obvious 这样做的方式" The others don't satisfy rule #1 ("美丽胜过丑陋 . ”)

  • 0

    尝试:

    from sys import stderr
    
    
    print >> sys.stderr, 'spam'
    
  • 18

    我发现这是唯一一个简短的灵活便携式可读:

    from __future__ import print_function
    import sys
    
    def eprint(*args, **kwargs):
        print(*args, file=sys.stderr, **kwargs)
    

    函数 eprint 可以与标准 print 函数相同的方式使用:

    >>> print("Test")
    Test
    >>> eprint("Test")
    Test
    >>> eprint("foo", "bar", "baz", sep="---")
    foo---bar---baz
    

相关问题