如何在 Python 中打印到 stderr?

有几种写 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)

这似乎与zen 的 Python#13 相矛盾,所以这里有什么区别,一种方式或另一种方式有什么优点或缺点?应该使用哪种方式?

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

答案

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

from __future__ import print_function
import sys

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

可以使用与标准print功能相同的方式使用eprint功能:

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz
import sys
sys.stderr.write()

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

编辑:“pythonic” 是我对可读性和性能的第三种思考…… 考虑到这两点,使用 python 80%的代码将是 pythonic。列表理解是不经常使用的 “大事”(可读性)。

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

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

还没有人提到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已被弃用 ,请改用logging.warning

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

我会说你的第一种方法:

print >> sys.stderr, 'spam'

是 “…… 一种显而易见的方式”,而另一种则不满足规则 1(“美丽胜于丑陋”。)

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

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

编辑事后看来,我认为与更改 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!')

您可以执行以下操作(来自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!")

不利的一面是在创建时将 sys.stderr 的值部分分配给包装的函数。这意味着, 如果您以后重定向 stderr,它将不会影响此功能。如果您打算重定向 stderr,请使用aaguirre在此页面上提到的 ** kwargs 方法。

在 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之外的任何内容。