如何打印到Python的标准错误?
我遇到至less三种打印到stderr的方法:
import sys print >> sys.stderr, 'spam' sys.stderr.write('spam\n') from __future__ import print_function print('spam', file=sys.stderr)
这似乎与Python#13 †的 禅宗相矛盾,所以最好的方法是什么? 这种或那种方式有什么优点或缺点?
† 应该有一个 – 而且最好只有一个 – 明显的方法来做到这一点。
我发现这是唯一一个短+灵活+便携+可读的:
from __future__ import print_function import sys def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs)
functioneprint
可以和标准print
function一样使用:
>>> print("Test") Test >>> eprint("Test") Test >>> eprint("foo", "bar", "baz", sep="---") foo---bar---baz
sys.stderr.write()
是我的select,只是更具可读性,并准确地说明你打算做什么和跨版本的移植。
编辑:“pythonic”是我在可读性和性能方面的第三个想法…考虑到这两件事情,python 80%的代码将pythonic。 列表理解是不常用的“大事”(可读性)。
对于Python 2,我的select是: print >> sys.stderr, 'spam'
因为您可以简单地打印列表/字典等,而不必将其转换为string。 print >> sys.stderr, {'spam': 'spam'}
而不是: sys.stderr.write(str({'spam': 'spam'}))
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
不是1:1的print
replace。
我会说你的第一个方法:
print >> sys.stderr, 'spam'
是“一个明显的做法”,其他人不满足规则1(“美丽胜于丑陋”)。
我使用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")
这将模仿标准的打印function,但在stderr上输出
def print_err(*args): sys.stderr.write(' '.join(map(str,args)) + '\n')
没有人提到logging
,但日志logging是专门为了传达错误消息而创build的。 默认情况下,它被设置为写入标准错误。 这个脚本:
# foo.py import logging logging.basicConfig(format='%(message)s') logging.warn('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')
编辑在后视中,我认为与sys.stderr不断更新的潜在混淆,并没有看到更新的行为,使得这个答案不如其他人指出的那样使用简单的函数。
使用部分只能保存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-的优先代码;.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!")
这个缺点是在创build时将sys.stderr的值赋给了被包装的函数。 这意味着, 如果稍后redirectstderr,则不会影响此function。 如果您打算redirectstderr,请使用此页面上的aaguirre提及的** kwargs方法。
这同样适用于stdout:
print 'spam' sys.stdout.write('spam\n')
正如在其他答案中所述, 打印提供了一个非常漂亮的界面,通常更方便(例如打印debugging信息),而写入速度更快,而且当您必须以某种方式精确地格式化输出时,打印也会更方便。 我也会考虑可维护性:
-
您稍后可能决定在stdout / stderr和常规文件之间切换。
-
print()语法在Python 3中已经改变了,所以如果你需要支持这两个版本, write()可能会更好。
我正在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]$
有用吗? 尝试将stderrredirect到一个文件,看看会发生什么:
[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给你的小小的介绍已经嗤之以鼻的地方(还有什么地方会去?)之外,它是有效的。
如果你做一个简单的testing:
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倍!