有几种方法可以写入 stderr:
print >> sys.stderr, "spam" # Python 2 only.
sys.stderr.write("spamn")
os.write(2, b"spamn")
from __future__ import print_function
print("spam", file=sys.stderr)
这些方法之间有什么区别?应该首选哪种方法?
我发现这是唯一一个简短,灵活,可移植且可读的:
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
import sys
sys.stderr.write()
是我的选择,只是更具可读性,并准确说明您打算做什么并跨版本移植。
编辑:对我来说,"pythonic"是关于可读性和性能的第三个想法......考虑到这两件事,使用 Python 80% 的代码将是 Pythonic。列表理解是不经常使用的"大事"(可读性(。
Python 3:
print("fatal error", file=sys.stderr)
蟒蛇 2:
print >> sys.stderr, "fatal error"
<小时 />长答案
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 errorn")
看起来更面向对象,并且优雅地从通用到具体。但请注意,write
不是 print
的 1:1 替代品。
人提到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 将包含印在 stdout 上的"hello world"。
对于Python 2,我的选择是: print >> sys.stderr, 'spam'
因为您可以简单地打印列表/字典等,而无需将其转换为字符串。 print >> sys.stderr, {'spam': 'spam'}
而不是: sys.stderr.write(str({'spam': 'spam'}))
说你的第一种方法:
print >> sys.stderr, 'spam'
是"一.显而易见的方法" 其他人不满足规则#1("美丽比丑陋好。
--2020年编辑 --
以上是我在 2011 年对 Python 2.7 的回答。现在Python 3是标准,我认为"正确"的答案是:
print("spam", file=sys.stderr)
我使用 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")
在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
之外不需要包含任何内容。
这将模仿标准打印功能,但在 stderr 上输出
def print_err(*args):
sys.stderr.write(' '.join(map(str,args)) + 'n')
编辑 事后看来,我认为更改 sys.stderr 和看不到更新的行为的潜在混淆使得这个答案不如像其他人指出的那样只使用一个简单的函数。
使用部分只能为您节省 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 中的代码(来检查它是否打印到 stderr 而不是 stdout:
# 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 方法。
同样适用于标准输出:
print 'spam'
sys.stdout.write('spamn')
如其他答案所述,打印提供了一个漂亮的界面,通常更方便(例如,用于打印调试信息(,而写入速度更快,并且当您必须以某种方式精确格式化输出时也可以更方便。我也会考虑可维护性:
您稍后可能会决定在 stdout/stderr 和常规文件之间切换。
print(( 语法在 Python 3 中发生了变化,所以如果你需要支持这两个版本,write(( 可能会更好。
我正在使用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(它还能去哪里?(,它有效。
如果由于致命错误而要退出程序,请使用:
sys.exit("Your program caused a fatal error. ... description ...")
并在标题中import sys
。
如果你做一个简单的测试:
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('Xn')
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 倍!
问题的答案是:在python中打印stdrr有不同的方法,但这取决于 1.(我们使用的是哪个Python版本 2.(我们想要的确切输出。
print和stderr的写入函数之间的区别:stderr :stderr(标准错误(是内置于每个 UNIX/Linux 系统中的管道,当您的程序崩溃并打印出调试信息(如 Python 中的回溯(时,它会转到 stderr 管道。
print:print 是一个格式化输入的包装器(输入是参数和末尾换行符之间的空格(,然后它调用给定对象的 write 函数,给定对象默认为 sys.stdout,但我们可以传递一个文件,即我们也可以在文件中打印输入。
蟒蛇2:如果我们使用的是 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 中检查上面的 sceario:
>>> import sys
>>> print("hi")
hi
在 Python 2.6 下,将来有一个导入,可以将打印成 功能。因此,为了避免任何语法错误和其他差异,我们 应该从将来的导入中启动我们使用 print(( 的任何文件 print_function。未来的导入仅适用于 Python 2.6 和 稍后,因此对于 Python 2.5 及更早版本,您有两种选择。您可以 将更复杂的打印转换为更简单的打印,或者您可以 使用在 Python2 和 蟒蛇3.
>>> from __future__ import print_function
>>>
>>> def printex(*args, **kwargs):
... print(*args, file=sys.stderr, **kwargs)
...
>>> printex("hii")
hii
>>>
案例:需要注意的是 sys.stderr.write(( 或 sys.stdout.write(( (标准输出(标准输出(是内置于每个 UNIX/Linux系统(不是打印的替代品,但是是的,我们可以使用 在某些情况下,它作为替代方案。打印是一个包装器,它包装 末尾带有空格和换行符的输入,并使用 write 函数 写。这就是 sys.stderr.write(( 更快的原因。
注意:我们还可以使用日志记录进行跟踪和调试
#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
我这样做只是为了好玩,但这是另一种方式...... :-(
message = 'error: Belly up!!'
print(message, file=sys.stderr if 'error' in message.lower() else sys.stdout)
另一种方式
import sys
print("{}".format(sys.exec_info()[1], file=sys.stderr)