如何在Python中打印到stderr?

问题:如何在Python中打印到stderr?

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

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

There are several ways to write to 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)

That seems to contradict zen of Python #13 , so what’s the difference here and are there any advantages or disadvantages to one way or the other? Which way should be used?

There should be one — and preferably only one — obvious way to do it.


回答 0

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

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

I found this to be the only one short + flexible + portable + readable:

from __future__ import print_function
import sys

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

The function eprint can be used in the same way as the standard print function:

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz

回答 1

import sys
sys.stderr.write()

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

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

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. list comprehension being the ‘big thing’ that isn’t used as often (readability).


回答 2

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

print >> sys.stderr is gone in Python3. http://docs.python.org/3.0/whatsnew/3.0.html says:

Old: print >> sys.stderr, "fatal error"
New: 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.


回答 3

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

Nobody’s mentioned logging yet, but logging was created specifically to communicate error messages. Basic configuration will set up a stream handler writing to 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.


回答 4

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

For Python 2 my choice is: print >> sys.stderr, 'spam' Because you can simply print lists/dicts etc. without convert it to string. print >> sys.stderr, {'spam': 'spam'} instead of: sys.stderr.write(str({'spam': 'spam'}))


回答 5

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

I did the following using 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")

回答 6

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

print >> sys.stderr, 'spam' 

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

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


回答 7

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

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

This will mimic the standard print function but output on stderr

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

回答 8

在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

In Python 3, one can just use 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.


回答 9

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

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.

Using partial only saves you 1 line of code. The potential confusion is not worth saving 1 line of code.

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

# 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. Which means, if you redirect stderr later it won’t affect this function. If you plan to redirect stderr, then use the **kwargs method mentioned by aaguirre on this page.


回答 10

同样适用于标准输出:

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

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

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

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

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 (e.g. 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. I would consider maintainability as well:

  1. You may later decide to switch between stdout/stderr and a regular file.

  2. print() syntax has changed in Python 3, so if you need to support both versions, write() might be better.


回答 11

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

I am working in 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:

[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.


回答 12

如果您做一个简单的测试:

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

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!


回答 13

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

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

import sys在标题中

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.


回答 14

问题的答案是:有两种不同的方法可以在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

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.

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: 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 i.e we can print the input in a file also.

Python2: If we are using python2 then

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

http://python3porting.com/noconv.html

If we check same above sceario in python3:

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

Under Python 2.6 there is a future import to make print into a function. So to avoid any syntax errors and other differences we should start any file where we use print() with from future import print_function. The future import only works under Python 2.6 and later, so for Python 2.5 and earlier you have two options. 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.

>>> 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. Print is a wrapper which wraps the input with space and newline at the end and uses the write function to write. This is the reason sys.stderr.write() is faster.

Note: we can also trace and debugg using 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