如何在Python中打印到stderr?

问题描述 投票:1149回答:16

有几种方法可以写入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†的禅宗相矛盾,那么这里有什么区别,这种方式有哪些优点或缺点?应该使用哪种方式?

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

python printing stderr zen-of-python
16个回答
988
投票

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

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

8
投票

在Python 3中,可以使用print():

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

几乎开箱即用:

import sys
print("Hello, world!", file=sys.stderr)

要么:

from sys import stderr
print("Hello, world!", file=stderr)

这很简单,除了sys.stderr之外不需要包含任何东西。


7
投票

这同样适用于stdout:

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

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

  1. 您可能稍后决定在stdout / stderr和常规文件之间切换。
  2. print()语法在Python 3中已经改变,所以如果你需要支持这两个版本,write()可能会更好。

6
投票

我在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(它还会去哪里?)之外,它的确有效。


3
投票

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

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倍!


0
投票

尝试:

from sys import stderr


print >> sys.stderr, 'spam' 

0
投票

问题的答案是:在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尾随逗号在Python3中变成了一个参数,所以如果我们使用尾随逗号来避免打印后的换行,这将在Python3中看起来像print('Text to print',end ='')这是Python2下的语法错误。

http://python3porting.com/noconv.html

如果我们在python 3中检查相同的上述场景:

>>> 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


-2
投票
import logging
logging.basicConfig(format='[%(levelname)s] %(message)s')

logging.error('is error, alarm!')
logging.warning('is simple waring')

print('hello')

pydoc日志记录


483
投票
import sys
sys.stderr.write()

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

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


131
投票

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


118
投票

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替代品。


88
投票

还没有人提到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.warn一直是deprecated,改用logging.warning


33
投票

我会说你的第一个方法:

print >> sys.stderr, 'spam' 

是“一个......显而易见的方式”其他人不满足规则#1(“美丽胜过丑陋。”)


30
投票

我使用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")

19
投票

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

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

17
投票

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

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

原版的

为了使它更容易,这里是一个使用'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的值分配给包装函数。这意味着,如果您稍后重定向stderr,它将不会影响此功能。如果您打算重定向stderr,请使用此页面上aaguirre提到的** kwargs方法。

© www.soinside.com 2019 - 2024. All rights reserved.