题 如何在Python 2中打印到stderr?


我至少有三种方法可以打印到stderr:

 import sys

 print >> sys.stderr, 'spam'

 sys.stderr.write('spam\n')

 from __future__ import print_function
 print('spam', file=sys.stderr)

这似乎是矛盾的 Python#13的禅宗  那么最好的方法是什么?这种或那种方式有任何优点或缺点吗?

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


991
2018-04-07 00:59


起源


列出的第一种方法是在Python 3中删除的许多内容之一。共识似乎是>>语法无论如何都是丑陋的,并且因为print现在是一个函数,所以语法永远不会起作用。 - Steve Howard
这是另一个要添加到列表中的内容: os.write(2, "spam\n") - Will Hardy
我使用:sys.exit('错误:<错误文本>') - stark
你可以使用 logging 图书馆和做 logger.error - Max Heiber


答案:


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

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

849
2018-02-20 13:31



这是 到目前为止 该 最好的选择因为它可以很好地为Python 3设置,即使你现在使用的是Python 2或Jython。 - Mark Booth
同意。这就是我用的全部。它是面向未来的,更一致的(pythonic)使用print作为函数,更清晰(即,到底是什么“>>”?这不是C ++ !! ;-))。 - JJC
只有一个想法:因为这将导入打印功能,原始脚本中的每个其他“打印”现在需要“功能化”添加“(”和“)”。所以这是对这种方法的轻微打击,IMO。 - Dan H
@DanH是的 军队 你可以让你的代码Python3准备就绪。我想这可能就是为什么许多人真的喜欢它! - MarcH
@MarkH ...是的,它迫使你让你的代码Python3准备就绪......它也迫使你现在这样做,只是为了向stderr打印一些调试信息...我会发现更多的麻烦大多数情况下我正在尝试调试某些东西。 (我宁愿不引入新的语法错误!):-) - Dan H


sys.stderr.write() 是我的选择,只是更具可读性,并准确地说明你打算做什么,并且可以跨版本移植。

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


400
2018-04-07 01:03



不可读性和pythonic一样吗? - Dheeraj V.S.
只是不要忘记冲洗。 - temoto
优势 print 声明很容易打印非字符串值,而不必先转换它们。如果你需要一个print语句,我建议你使用第三个选项来准备python 3 - vdboor
sys.stderr.write() 没什么 print。它不会添加换行符。 - Colonel Panic
@temoto - stderr没有缓冲,所以不需要刷新。 - Matt


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


120
2017-11-08 17:29



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


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


98
2018-04-04 10:00





没有人提到过 logging 但是,日志记录是专门为传达错误消息而创建的。默认情况下,它设置为写入stderr。这个脚本:

# 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 包含'你好世界')


53
2017-12-23 16:04



好点!这是“实现它的一种方法”我不知道为什么每个人都使用日志记录时,每个人都使用了已接受的答案。 - jamylak
根据我的经验,更多人使用print来记录消息而不是使用日志记录。我认为python4应该只是从语言中删除打印并强制您使用日志记录。 - Mnebuerquo
为什么每个人都想“强迫”人们做事?你希望你是绝地吗? - skia.heliou


我会说你的第一个方法:

print >> sys.stderr, 'spam' 

是这一个 。 。 。 明显 这样做的方式“其他人不满足规则#1(”美丽胜过丑陋。“)


32
2018-04-07 01:05



意见不同。这是最少的 明显 对我来说。 - porgarmingduod
@AliVeli没有括号,这是一个较旧的Python <= 2语法,因此不兼容Python 3。 - Rebs
我会说这是所有3个中最丑陋的版本 - volcano
那是什么 >> 语法上的意思?我知道这是复制bash的努力 >那么这样做是为了做些什么? - Dmytro Sirenko
@EarlGray这是来自C ++的流插入运算符的保留: std::cout << "spam"; - Sean Allred


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

28
2017-12-29 21:40



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


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

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

18
2017-10-06 07:42



我会添加一个sys.stderr.flush() - AMS
@AMS - 为什么? print 不包括同花顺。 - Robᵩ
为什么你可以真正模仿它? - Mad Physicist


编辑 在后视中,我认为改变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!')

您可以通过执行以下操作来检查它是否正在打印到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!")

这方面的缺点是局部的 受让人 sys.stderr在创建时对包装函数的值。意思是, 如果您稍后重定向stderr它将不会影响此功能。 如果您计划重定向stderr,则使用提到的** kwargs方法 aaguirre 在本页。


16
2017-12-30 02:13



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


这同样适用于stdout:

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

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

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

  2. 打印() 语法在Python 3中已更改,因此如果您需要支持这两个版本, 写() 可能会更好。


6
2017-11-01 11:58



运用 from __future__ import print_function 是支持Python 2.6+和Python 3的更好方法。 - phoenix


我在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(它还会去哪里?)之外,它有效。


4
2018-02-10 02:29