1608

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

†</sup>应该有一种——最好只有一种——明显的方法。

4

16 回答 16

1405

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

# This line only if you still care about Python2
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
于 2013-02-20T13:31:54.223 回答
623
import sys
sys.stderr.write()

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

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

于 2011-04-07T01:03:21.727 回答
300

蟒蛇2:

print >> sys.stderr, "fatal error"

蟒蛇 3:

print("fatal error", file=sys.stderr)

长答案

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

旧:print >> sys.stderr, "fatal error"
新:print("fatal error", file=sys.stderr)

对于我们中的许多人来说,将目的地放在命令的末尾有点不自然。替代方案

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

看起来更面向对象,并且优雅地从通用到特定。但请注意,这write不是print.

于 2013-04-04T10:00:16.273 回答
171

还没有人提到logging,但日志记录是专门为传达错误消息而创建的。基本配置将设置一个写入 stderr 的流处理程序。

这个脚本:

# foo.py
import logging

logging.basicConfig(format='%(message)s')
log = logging.getLogger(__name__)
log.warning('I print to stderr by default')
print('hello world')

在命令行上运行时有以下结果:

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

bar.txt将包含打印在标准输出的“hello world”。

于 2016-12-23T16:04:44.133 回答
132

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

于 2011-11-08T17:29:52.050 回答
49

我会说你的第一种方法:

print >> sys.stderr, 'spam' 

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

-- 2020 年编辑 --

以上是我在 2011 年对 Python 2.7 的回答。既然 Python 3 是标准,我认为“正确”的答案是:

print("spam", file=sys.stderr) 
于 2011-04-07T01:05:24.923 回答
38

我使用 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")
于 2013-12-29T21:40:08.073 回答
26

在 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

于 2019-01-08T06:57:09.190 回答
21

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

def print_err(*args):
    sys.stderr.write(' '.join(map(str,args)) + '\n')
于 2012-10-06T07:42:50.217 回答
17

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

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

原来的

为了使它更容易,这里有一个使用“部分”的版本,这对包装函数有很大帮助。

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-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 方法。

于 2013-12-30T02:13:49.073 回答
6

这同样适用于标准输出:

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

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

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

  2. Python 3 中的print()语法发生了变化,因此如果您需要同时支持这两个版本,write()可能会更好。

于 2012-11-01T11:58:08.173 回答
4

我正在使用 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(它还能去哪里?)这一事实之外,它可以工作。

于 2016-02-10T02:29:27.367 回答
3

如果由于致命错误而要退出程序,请使用:

sys.exit("Your program caused a fatal error. ... description ...")

import sys在标题中。

于 2019-11-26T11:59:34.467 回答
2

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

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

于 2012-06-12T17:17:38.713 回答
-2

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

print 和 stderr 的 write 函数之间的区别: 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

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

http://python3porting.com/noconv.html

如果我们在 python3 中检查上述相同的情况:

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

在 Python 2.6 下有一个未来的导入来将 print 变成一个函数。因此,为了避免任何语法错误和其他差异,我们应该从将来导入 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

于 2018-01-30T13:17:47.670 回答
-3

我这样做只是为了好玩,但这是另一种方式...... :-)

message = 'error: Belly up!!'
print(message, file=sys.stderr if 'error' in message.lower() else sys.stdout)
于 2022-01-13T22:04:54.247 回答