如何在Python中打印到stderr?


1338

有几种写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 相矛盾,所以这里有什么区别,一种方法或另一种方法有什么优点或缺点?应该使用哪种方式?

应该有一种(最好只有一种)明显的方式来做到这一点。


46
列出的第一种方法是Python 3中删除的许多东西之一。共识似乎是>>语法无论如何都是丑陋的,并且由于print现在是一个函数,因此该语法永远无法使用。
史蒂夫·霍华德

23
我使用:sys.exit( '错误:<错误文本>')
鲜明

1
只需使用打印。
PythonMaster202 '19

Answers:


1165

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

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

29
只是一个想法:由于这将导入打印功能,因此现在需要对原始脚本中的所有其他“打印”进行“功能化”并添加“(”和“)”。因此,IMO对这种方法略有打击。
Dan H

45
@DanH是的,这迫使您使您的代码可以使用Python3。我想这可能就是为什么很多人真正喜欢它的原因!
MarcH 2014年

18
@MarkH ...是的,它迫使您将代码编写为Python3就绪的...它也迫使您现在进行操作,只是将一些调试信息打印到stderr ...我会发现更多麻烦之处在大多数情况下,当我尝试调试某些东西时。(我宁愿不引入新的语法错误!):-)
Dan H

29
FWIW此代码不会强制您print在整个程序中使用的功能版本。仅在包含定义的模块中eprint()。单独将其放入一个小文件中,然后将其eprint从其他文件导入,您可以根据需要继续使用语句print
亚历克西斯

3
同样,从打印转换为打印功能是一个简单的查找替换,2to3已经为您自动进行了替换。如果还没有,那就做吧;python2将在不到2年的时间内消失……2到3之间的某些事情可能会变得有些棘手。打印功能不是其中之一。参见docs.python.org/2/library/2to3.html
bobpaul

548
import sys
sys.stderr.write()

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

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


88
只是不要忘记冲洗。
temoto 2012年

10
print语句的优点是易于打印非字符串值,而无需先转换它们。如果您需要打印语句,那么我建议您使用第3个选项来准备python 3
vdboor'4

56
sys.stderr.write()真不像print。它不会添加换行符。
Panic Panic

41
@temoto-stderr未缓冲,因此无需刷新。
马特2013年

11
@SkipHuffman你的意思是os.linesepstderr毕竟这是我们在谈论的。不想让控制台弄错错误的换行符。
jpmc26 2015年

179

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


5
我想这是一个偏爱的问题,但是我看不出有什么丑陋的地方print('spam', file=sys.stderr)。如果您要一遍又一遍地进行操作,则可以像最流行的答案一样对“ eprint”功能进行编码,但是在这种情况下,我会问,日志记录出了什么问题?stackoverflow.com/a/41304513/1450294
Michael Scheper

澄清意图的另一种方法是with sys.stderr as dest:在缩进电话print("ERROR", file=dest)
MarkHu

130

还没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将包含“世界你好”在标准输出。


2
以我的经验,使用打印记录消息的人数要多于使用记录的人数。我认为python4应该只是从语言中删除打印,并强迫您为此使用日志记录。
Mnebuerquo

1
这是最好的答案!...我在打印或sys方面苦苦挣扎,或者谁知道...何时需要适当的日志记录...感谢这个好主意
Carlos Saltos

129

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


6
"{0}".format({'spam': 'spam'})无论如何,用Python风格打印字典的方式不是吗?我会说您应该避免显式转换为字符串。编辑:我不小心语法
luketparkinson 2012年

1
@luketparkinson都是关于调试的-因此,我认为,最好使用最简单的代码。
Frankovskyi Bogdan

88
这在Python 3上不起作用,因此您应该在新代码中避免使用它。
JonnyJD

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

2
我打算建议您也可以使用局部函数,但要意识到局部函数在局部函数创建时会将stderr分配给该函数。这样可以防止您稍后重定向stderr,因为局部对象仍将保留原始stderr对象。
Rebs

31

我要说的是您的第一种方法:

print >> sys.stderr, 'spam' 

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


109
意见不同。这对我来说是最不明显的
porgarmingduod 2011年

4
@AliVeli没有括号,这是较旧的Python <= 2语法,因此与Python 3不兼容。
Rebs

30
我会说这是所有3座
火山中

4
这在>>语法上是什么意思?我知道这是复制bash的工作>,所以这样做有些shoe脚的语法吗?
Dmytro Sirenko 2014年

2
@EarlGray这是C ++流插入运算符的保留:std::cout << "spam";
Sean Allred


19

在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


16

编辑在事后看来,我认为与更改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方法。


Corey Goldberg的代码是否最好在Rube Goldberg机器上运行?:P
Agi Hammerthief 2015年

1
顺便说一句:如果您想更多地了解“部分”,“ currying”是一个(更)有用的搜索关键字。
MarcH 2015年

5

同样适用于标准输出:

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

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

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

  2. 在Python 3中,print()语法已更改,因此,如果您需要同时支持两个版本,则write()可能会更好。


4
使用from __future__ import print_function是同时支持Python 2.6+和Python 3的更好方法。–
凤凰城

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(它还能去哪里?)之外,它还是可以工作的。


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


如果运行此命令,我看到的差别要小得多。有趣的是,大多数答案都忽略了print函数(python 3)方式。我以前从未使用过(惯性),但以为我会运行此计时脚本并添加打印功能。打印语句和函数的直接比较是不可能的(从进口未来适用于整个文件和面具print语句),但重写这段代码使用打印功能,而不是声明我看到一个更大的加速(〜1.6虽然有点变),以支持打印功能。
hamish 2012年

1
该测试的结果在某种程度上具有误导性。打印“ XXXXXXXXXXXXXXXXXXXX”而不是“ X”,该比率降至1.05。我认为大多数python程序都需要打印多个字符。
总是

14
我不关心性能,例如打印警告。
2013年

我知道已经有一段时间了,但是您在我的帖子之后很久就回答了...如果您不关心性能,我建议使用更pythonic的方法是使用sys.stderr.write而不是WTF ?!“ >>”字符。如果此sys.stdout命名空间太长,则可以重命名...(即从sys import stderr导入为stderr_fh)。然后,您可以执行stderr_fh.write(“ blah”)
ThePracticalOne 2014年

1
[3/3]即使该基准测试更为准确,也可能不值得担心。正如Knuth所说:“程序员浪费大量时间来思考或担心程序非关键部分的速度,而这些效率的尝试实际上在考虑调试和维护时会产生很大的负面影响。我们应该忽略一些小问题。效率大约是97%的时间:过早的优化是万恶之源。”
科里·戈德堡

1

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

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

import sys在标题中


-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中的Python2尾部逗号已成为参数,因此,如果我们使用尾部逗号来避免打印后出现换行符,则在Python3中,这将类似于print('Text to print',end =''),这是Python2下的语法错误。

http://python3porting.com/noconv.html

如果我们在python3的sceario上进行相同的检查:

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

在Python 2.6下,有一个将来的导入可以使打印成为函数。因此,为避免任何语法错误和其他差异,我们应该从以后的 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,但是可以。在某些情况下,我们可以将其用作替代方案。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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.