简体   繁体   English

如何在 Python 中打印到 stderr?

[英]How to print to stderr in Python?

There are several ways to write to stderr:有几种方法可以写入 stderr:

print >> sys.stderr, "spam"  # Python 2 only.

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

os.write(2, b"spam\n")

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

What are the differences between these methods?这些方法之间有什么区别? Which method should be preferred?应该首选哪种方法?

I found this to be the only one short, flexible, portable and readable:我发现这是唯一一个简短、灵活、便携和可读的:

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

The optional function eprint saves some repetition.可选功能eprint节省了一些重复。 It can be used in the same way as the standard print function:它可以像标准print功能一样使用:

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz
import sys
sys.stderr.write()

Is my choice, just more readable and saying exactly what you intend to do and portable across versions.是我的选择,只是更具可读性,准确地说出您打算做什么,并且可以跨版本移植。

Edit: being 'pythonic' is a third thought to me over readability and performance... with these two things in mind, with python 80% of your code will be pythonic.编辑:成为“pythonic”是我对可读性和性能的第三个想法……考虑到这两件事,使用 python,你的代码的 80% 将是 pythonic。 list comprehension being the 'big thing' that isn't used as often (readability).列表理解是不经常使用的“大事”(可读性)。

Python 2:蟒蛇2:

print >> sys.stderr, "fatal error"

Python 3:蟒蛇 3:

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

Long answer长答案

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

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

For many of us, it feels somewhat unnatural to relegate the destination to the end of the command.对于我们中的许多人来说,将目的地放在命令的末尾有点不自然。 The alternative替代方案

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

looks more object oriented, and elegantly goes from the generic to the specific.看起来更面向对象,并且优雅地从通用到特定。 But note that write is not a 1:1 replacement for print .但请注意, write不是print的 1:1 替代品。

Nobody's mentioned logging yet, but logging was created specifically to communicate error messages.还没有人提到logging ,但日志记录是专门为传达错误消息而创建的。 Basic configuration will set up a stream handler writing to stderr.基本配置将设置一个写入 stderr 的流处理程序。

This script:这个脚本:

# foo.py
import logging

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

has the following result when run on the command line:在命令行上运行时有以下结果:

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

and bar.txt will contain the 'hello world' printed on stdout. bar.txt将包含打印在标准输出上的“hello world”。

For Python 2 my choice is: print >> sys.stderr, 'spam' Because you can simply print lists/dicts etc. without convert it to string.对于Python 2 ,我的选择是: print >> sys.stderr, 'spam'因为您可以简单地打印列表/字典等,而无需将其转换为字符串。 print >> sys.stderr, {'spam': 'spam'} instead of: sys.stderr.write(str({'spam': 'spam'})) print >> sys.stderr, {'spam': 'spam'}而不是: sys.stderr.write(str({'spam': 'spam'}))

I would say that your first approach:我会说你的第一种方法:

print >> sys.stderr, 'spam' 

is the "One . . . obvious way to do it" The others don't satisfy rule #1 ("Beautiful is better than ugly.")是“一个……显而易见的方法”其他不满足规则#1(“美丽胜于丑陋。”)

-- Edit for 2020 -- -- 2020 年编辑 --

Above was my answer for Python 2.7 in 2011. Now that Python 3 is the standard, I think the "right" answer is:以上是我在 2011 年对 Python 2.7 的回答。既然 Python 3 是标准,我认为“正确”的答案是:

print("spam", file=sys.stderr) 

I did the following using Python 3:我使用 Python 3 执行了以下操作:

from sys import stderr

def print_err(*args, **kwargs):
    print(*args, file=stderr, **kwargs)

So now I'm able to add keyword arguments, for example, to avoid carriage return:所以现在我可以添加关键字参数,例如,以避免回车:

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

In Python 3, one can just use print():在 Python 3 中,可以只使用print():

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

almost out of the box:几乎开箱即用:

import sys
print("Hello, world!", file=sys.stderr)

or:或者:

from sys import stderr
print("Hello, world!", file=stderr)

This is straightforward and does not need to include anything besides sys.stderr .这很简单,不需要包含除sys.stderr之外的任何内容。

This will mimic the standard print function but output on stderr这将模仿标准打印功能,但在 stderr 上输出

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

EDIT In hind-sight, I think the potential confusion with changing sys.stderr and not seeing the behaviour updated makes this answer not as good as just using a simple function as others have pointed out.编辑事后看来,我认为更改 sys.stderr 并且没有看到行为更新的潜在混淆使得这个答案不如其他人指出的那样仅仅使用简单的函数。

Using partial only saves you 1 line of code.使用 partial 只会为您节省 1 行代码。 The potential confusion is not worth saving 1 line of code.潜在的混乱不值得保存 1 行代码。

original原来的

To make it even easier, here's a version that uses 'partial', which is a big help in wrapping functions.为了使它更容易,这里有一个使用“部分”的版本,这对包装函数有很大帮助。

from __future__ import print_function
import sys
from functools import partial

error = partial(print, file=sys.stderr)

You then use it like so然后你像这样使用它

error('An error occured!')

You can check that it's printing to stderr and not stdout by doing the following (over-riding code from http://coreygoldberg.blogspot.com.au/2009/05/python-redirect-or-turn-off-stdout-and.html ):您可以通过执行以下操作检查它是否打印到标准错误而不是标准输出(来自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!")

The downside to this is partial assigns the value of sys.stderr to the wrapped function at the time of creation.这样做的缺点是在创建时将 sys.stderr 的值部分分配给包装函数。 Which means, if you redirect stderr later it won't affect this function.这意味着,如果您稍后重定向 stderr 它不会影响此功能。 If you plan to redirect stderr, then use the **kwargs method mentioned by aaguirre on this page.如果您打算重定向 stderr,请使用aaguirre在此页面上提到的 **kwargs 方法。

The same applies to stdout:这同样适用于标准输出:

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

As stated in the other answers, print offers a pretty interface that is often more convenient (eg for printing debug information), while write is faster and can also be more convenient when you have to format the output exactly in certain way.如其他答案所述, print提供了一个漂亮的界面,通常更方便(例如,用于打印调试信息),而write更快,并且当您必须以某种方式精确格式化输出时也更方便。 I would consider maintainability as well:我也会考虑可维护性:

  1. You may later decide to switch between stdout/stderr and a regular file.您稍后可能会决定在 stdout/stderr 和常规文件之间切换。

  2. print() syntax has changed in Python 3, so if you need to support both versions, write() might be better. Python 3 中的print()语法发生了变化,因此如果您需要同时支持这两个版本, write()可能会更好。

I am working in python 3.4.3.我正在使用 python 3.4.3。 I am cutting out a little typing that shows how I got here:我正在删减一些显示我是如何到达这里的打字:

[18:19 jsilverman@JSILVERMAN-LT7 pexpect]$ python3
>>> import sys
>>> print("testing", file=sys.stderr)
testing
>>>
[18:19 jsilverman@JSILVERMAN-LT7 pexpect]$ 

Did it work?它奏效了吗? Try redirecting stderr to a file and see what happens:尝试将 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]$

Well, aside from the fact that the little introduction that python gives you has been slurped into stderr (where else would it go?), it works.好吧,除了 python 给你的小介绍已经被stderr(它还能去哪里?)这一事实之外,它可以工作。

If you want to exit a program because of a fatal error, use:如果由于致命错误而要退出程序,请使用:

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

and import sys in the header.并在标题中import sys

If you do a simple test:如果你做一个简单的测试:

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

You will find that sys.stderr.write() is consistently 1.81 times faster!您会发现 sys.stderr.write() 始终快1.81倍!

Another way另一种方式

import sys
print("{}".format(sys.exec_info()[1], file=sys.stderr)

Answer to the question is : There are different way to print stderr in python but that depends on 1.) which python version we are using 2.) what exact output we want.问题的答案是:在 python 中打印 stderr 有不同的方法,但这取决于 1.) 我们使用的是哪个 python 版本 2.) 我们想要什么确切的输出。

The differnce between print and stderr's write function: stderr : stderr (standard error) is pipe that is built into every UNIX/Linux system, when your program crashes and prints out debugging information (like a traceback in Python), it goes to the stderr pipe. print 和 stderr 的 write 函数之间的区别: stderr : stderr(标准错误)是每个 UNIX/Linux 系统中内置的管道,当您的程序崩溃并打印出调试信息(如 Python 中的回溯)时,它会转到 stderr管道。

print : print is a wrapper that formats the inputs (the input is the space between argument and the newline at the end) and it then calls the write function of a given object, the given object by default is sys.stdout, but we can pass a file ie we can print the input in a file also. print : print 是一个包装器,它格式化输入(输入是参数和末尾换行符之间的空格),然后它调用给定对象的 write 函数,给定对象默认是 sys.stdout,但我们可以传递一个文件,即我们也可以在文件中打印输入。

Python2: If we are using python2 then Python2:如果我们使用的是 python2 那么

>>> import sys
>>> print "hi"
hi
>>> print("hi")
hi
>>> print >> sys.stderr.write("hi")
hi

Python2 trailing comma has in Python3 become a parameter, so if we use trailing commas to avoid the newline after a print, this will in Python3 look like print('Text to print', end=' ') which is a syntax error under Python2. Python2 尾随逗号在 Python3 中已成为参数,因此如果我们使用尾随逗号来避免打印后的换行符,这在 Python3 中将看起来像 print('Text to print', end=' ') ,这是 Python2 下的语法错误.

http://python3porting.com/noconv.html http://python3porting.com/noconv.html

If we check same above sceario in python3:如果我们在 python3 中检查上述相同的情况:

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

Under Python 2.6 there is a future import to make print into a function.在 Python 2.6 下有一个未来的导入来将 print 变成一个函数。 So to avoid any syntax errors and other differences we should start any file where we use print() with from future import print_function.因此,为了避免任何语法错误和其他差异,我们应该从将来导入 print_function 开始使用 print() 的任何文件。 The future import only works under Python 2.6 and later, so for Python 2.5 and earlier you have two options.未来的导入仅适用于 Python 2.6 及更高版本,因此对于 Python 2.5 及更早版本,您有两种选择。 You can either convert the more complex print to something simpler, or you can use a separate print function that works under both Python2 and Python3.您可以将更复杂的打印转换为更简单的打印,也可以使用在 Python2 和 Python3 下都可以使用的单独打印函数。

>>> from __future__ import print_function
>>> 
>>> def printex(*args, **kwargs):
...     print(*args, file=sys.stderr, **kwargs)
... 
>>> printex("hii")
hii
>>>

Case: Point to be noted that sys.stderr.write() or sys.stdout.write() ( stdout (standard output) is a pipe that is built into every UNIX/Linux system) is not a replacement for print, but yes we can use it as a alternative in some case.案例:需要注意的是 sys.stderr.write() 或 sys.stdout.write() (stdout(标准输出)是一个内置在每个 UNIX/Linux 系统中的管道)不是打印的替代品,但是是的在某些情况下,我们可以将其用作替代方案。 Print is a wrapper which wraps the input with space and newline at the end and uses the write function to write. Print 是一个包装器,它在最后用空格和换行符包装输入,并使用 write 函数进行写入。 This is the reason sys.stderr.write() is faster.这就是 sys.stderr.write() 更快的原因。

Note: we can also trace and debugg using Logging注意:我们还可以使用 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 https://docs.python.org/2/library/logging.html#logger-objects

import logging
logging.basicConfig(format='[%(levelname)s] %(message)s')

logging.error('is error, alarm!')
logging.warning('is simple waring')

print('hello')

pydoc logging pydoc日志记录

Im doing this just for fun but here is another way... :-)我这样做只是为了好玩,但这是另一种方式...... :-)

message = 'error: Belly up!!'
print(message, file=sys.stderr if 'error' in message.lower() else sys.stdout)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM