如何在Python中打印到stderr?

wim*_*wim 1246 python printing stderr zen-of-python

有几种方法可以写入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)
Run Code Online (Sandbox Code Playgroud)

这似乎与Python#13 †的禅宗相矛盾,那么这里有什么区别,这种方式有哪些优点或缺点?应该使用哪种方式?

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

Mar*_*rcH 1076

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

from __future__ import print_function
import sys

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)
Run Code Online (Sandbox Code Playgroud)

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

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz
Run Code Online (Sandbox Code Playgroud)

  • @DanH是的,这*强迫你让你的代码Python3就绪.我想这可能就是为什么许多人真的喜欢它! (38认同)
  • 只有一个想法:因为这将导入打印功能,原始脚本中的每个其他"打印"现在需要"功能化"添加"("和")".所以这是对这种方法的轻微打击,IMO. (28认同)
  • FWIW此代码**不会强迫您在整个程序中使用`print`的功能版本.仅在包含`eprint()`定义的模块中.把它放在一个小文件中,将`eprint`从它导入到你的其他文件中,你可以继续使用语句`print`,只要你愿意. (24认同)
  • @MarkH ...是的,它迫使你让你的代码Python3准备就绪......它也迫使你现在就去做,只是打印一些调试信息到stderr ...我会发现更多的麻烦大多数情况下我正在尝试调试某些东西.(我宁愿不介绍新的语法错误!):-) (18认同)
  • 此外,您从打印转换为打印功能是一个简单的查找替换,2to3 已经为您自动化。如果你还没有,就已经这样做了;python2 将在不到 2 年的时间内消失...... 2 到 3 之间的一些事情可能会变得有点棘手;打印功能不是其中之一。见 https://docs.python.org/2/library/2to3.html (5认同)
  • 为了记录,这不适用于python 2.4 (2认同)
  • 如果您将 `eprint` 编写为类方法,请不要忘记添加 `self` 作为参数:`def eprint(self, *args, **kwargs):`。否则你的输出会变得混乱,并且可能需要一段时间才能找出原因:-) (2认同)

Mik*_*rez 514

import sys
sys.stderr.write()
Run Code Online (Sandbox Code Playgroud)

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

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

  • 只是不要忘记冲洗. (80认同)
  • `sys.stderr.write()`与`print`完全不同.它不会添加换行符. (54认同)
  • @temoto - stderr没有缓冲,所以不需要刷新. (36认同)
  • 不可读性和pythonic一样吗? (26认同)
  • `print`语句的优点是可以轻松打印非字符串值,而无需先进行转换.如果你需要一个print语句,我建议你使用第3个选项来准备python 3 (10认同)
  • @SkipHuffman你的意思是`os.linesep`.毕竟,这是我们正在谈论的"stderr".不希望控制台搞乱错误的换行符. (9认同)
  • 这适用于Python 2和3,如果你想同时支持它们,这很重要. (7认同)
  • 不添加新行吗?只需将+'\n'放在最后. (6认同)
  • 即使将stderr重定向到文件,你确定@Matt是否适用? (4认同)
  • @Dheeraj是和否,对我来说pythonic正在优雅地使用该语言,同时保持可读性.一些简单的list/dict comprehensions复合语句比for循环更加pythonic,我尝试选择更常见,更长的版本.我不会称之为pythonic. (3认同)
  • 这个建议有我的投票.从未来导入可能会破坏其他代码,并且没有奇怪的语法. (2认同)
  • @temoto 是的。/长度 (2认同)
  • 要记录这样的异常,请使用sys.stderr.write(traceback.format_exc())。 (2认同)

Joa*_*m W 139

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)
Run Code Online (Sandbox Code Playgroud)

不幸的是,这非常难看.或者,使用

sys.stderr.write("fatal error\n")
Run Code Online (Sandbox Code Playgroud)

但请注意,这write不是1:1的替代品print.

  • 我想这是一个偏好问题,但是我看不出`print('spam',file = sys.stderr)`有什么丑陋之处。如果您要一遍又一遍地进行操作,则可以像最流行的答案一样对“ eprint”功能进行编码,但是在这种情况下,我想问一下,日志记录出了什么问题?/sf/answers/2891315941/ (4认同)
  • 另一种澄清意图的方法是在缩进调用“print("ERROR", file=dest)”之前执行“with sys.stderr as dest:” (2认同)

Fra*_*dan 129

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

  • 这在Python 3上不起作用,因此您应该在新代码中避免使用它. (87认同)
  • 打印字典的Pythonic方式更像是"{0}".格式({'spam':'spam'})`不管怎样,不是吗?我会说你应该避免显式转换为字符串.编辑:我不小心写了一个语法 (6认同)
  • @luketparkinson 这一切都与调试有关 - 所以,我认为,最好尽可能使用最简单的代码。 (2认同)

slu*_*shy 107

还没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')
Run Code Online (Sandbox Code Playgroud)

在命令行上运行时,结果如下:

$ python3 foo.py > bar.txt
I print to stderr by default
Run Code Online (Sandbox Code Playgroud)

(和bar.txt包含'hello world')

(注意,logging.warn已被弃用,请logging.warning改用)

  • 根据我的经验,更多的人使用打印来记录消息而不是使用日志记录。我认为 python4 应该只是从语言中删除打印并强制您为此使用日志记录。 (4认同)
  • 这就是最好的答案!!...我在打印或系统方面遇到了困难,或者谁知道...何时需要适当的日志记录...谢谢你的好主意 (2认同)

Car*_* F. 31

我会说你的第一个方法:

print >> sys.stderr, 'spam' 
Run Code Online (Sandbox Code Playgroud)

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

  • 意见不同.这对我来说是最不明显的__obvious__. (106认同)
  • 我会说这是所有3个中最丑陋的版本 (27认同)
  • @AliVeli没有括号,这是一个较旧的Python <= 2语法,因此不兼容Python 3. (4认同)
  • 那个`>>`在语法上意味着什么?我知道这是一个复制bash的`>`的努力,所以这样做是为了做些什么? (4认同)
  • @EarlGray,事情就是这样。[语法](https://docs.python.org/2/reference/grammar.html) 表示打印语句是 `print &lt;stuff&gt;` 或 `print &gt;&gt; &lt;stuff&gt;`。 (2认同)
  • @EarlGray这是来自C++的流插入运算符的保留:`std :: cout <<"spam";` (2认同)
  • 打印&gt;&gt; sys.stderr,“测试”不再起作用(python3) (2认同)
  • 是什么让这一切如此美丽?它看起来就像是把非 python 编程语言乱七八糟地扔进 python 中,只是为了支持 print 作为语句。这当然是他们取消打印声明的原因之一。 (2认同)
  • 2020 版本已经尽善尽美了(: (2认同)

aag*_*rre 31

我使用Python 3做了以下事情:

from sys import stderr

def print_err(*args, **kwargs):
    print(*args, file=stderr, **kwargs)
Run Code Online (Sandbox Code Playgroud)

所以现在我可以添加关键字参数,例如,以避免回车:

print_err("Error: end of the file reached. The word ", end='')
print_err(word, "was not found")
Run Code Online (Sandbox Code Playgroud)

  • 我打算建议你也可以使用部分,但是意识到在部分创建时部分将stderr指定给函数.这可以防止您稍后重定向stderr,因为partial仍将保留原始stderr对象. (2认同)

小智 19

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

def print_err(*args):
    sys.stderr.write(' '.join(map(str,args)) + '\n')
Run Code Online (Sandbox Code Playgroud)

  • 我会添加一个sys.stderr.flush() (8认同)
  • @AMS - 为什么?`print`不包括同花顺. (4认同)
  • 为什么模仿你什么时候才能真正做到? (4认同)

Reb*_*ebs 16

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

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

原版的

为了使它更容易,这里是一个使用'partial'的版本,这对包装函数有很大帮助.

from __future__ import print_function
import sys
from functools import partial

error = partial(print, file=sys.stderr)
Run Code Online (Sandbox Code Playgroud)

然后你就这样使用它

error('An error occured!')
Run Code Online (Sandbox Code Playgroud)

您可以通过执行以下操作来检查它是否打印到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!")
Run Code Online (Sandbox Code Playgroud)

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

  • Corey Goldberg 的代码最好在 Rube Goldberg 机器上运行吗?:P (2认同)
  • 顺便说一句:如果您想了解更多关于“部分”的信息,“currying”是一个(更)有用的搜索关键字。 (2认同)

Flo*_*ane 11

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

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
Run Code Online (Sandbox Code Playgroud)

几乎开箱即用:

import sys
print("Hello, world!", file=sys.stderr)
Run Code Online (Sandbox Code Playgroud)

要么:

from sys import stderr
print("Hello, world!", file=stderr)
Run Code Online (Sandbox Code Playgroud)

这很简单,不需要除以外的任何内容sys.stderr


Sep*_*rvi 5

这同样适用于stdout:

print 'spam'
sys.stdout.write('spam\n')
Run Code Online (Sandbox Code Playgroud)

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

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

  2. print()语法在Python 3中已经改变,所以如果你需要支持这两个版本,write()可能会更好.

  • 使用`from __future__ import print_function`是支持Python 2.6+和Python 3的更好方法. (4认同)

Jef*_*man 5

我在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]$ 
Run Code Online (Sandbox Code Playgroud)

它有用吗?尝试将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]$
Run Code Online (Sandbox Code Playgroud)

好吧,除了python给你的小介绍已经悄悄进入stderr(它还会去哪里?)之外,它的确有效.


fel*_*i_x 5

如果您想因致命错误而退出程序,请使用:

sys.exit("Your program caused a fatal error. ... description ...")
Run Code Online (Sandbox Code Playgroud)

import sys在标题中。