关于打印:如何在python中打印到stderr?

How to print to stderr in Python?

有几种方法可以写入stderr:

1
2
3
4
5
6
7
8
9
10
11
 # Note: this first one does not work in Python 3
 print >> sys.stderr,"spam"

 sys.stderr.write("spam
"
)

 os.write(2, b"spam
"
)

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

这似乎与Python禅宗相矛盾?那么,这里的区别是什么呢?这两种方法有什么优缺点吗?应该采用哪种方式?

应该有一种——最好只有一种——显而易见的方法来做到这一点。


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

1
2
3
4
5
from __future__ import print_function
import sys

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

函数eprint的使用方式与标准print函数相同:

1
2
3
4
5
6
>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo","bar","baz", sep="---")
foo---bar---baz


1
2
import sys
sys.stderr.write()

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

编辑:在我看来,"Python"是第三种关于可读性和性能的想法…考虑到这两件事,有了Python,80%的代码将是pythonic。列表理解是一个"大问题",并不是经常使用(可读性)。


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


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

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

不幸的是,这很难看。或者,使用

1
2
sys.stderr.write("fatal error
"
)

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


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

1
2
3
4
5
6
7
# 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')

在命令行上运行时产生以下结果:

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

(bar.txt包含"你好世界")。

(注:logging.warn已被否决,改用logging.warning)


我想说你的第一个方法是:

1
print >> sys.stderr, 'spam'

是"一"。…"其他人不满足规则1"("美胜于丑")显然是这样做的方法。


我使用python 3执行了以下操作:

1
2
3
4
from sys import stderr

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

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

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


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

1
2
3
def print_err(*args):
    sys.stderr.write(' '.join(map(str,args)) + '
'
)


事后再编辑一下,我认为改变sys.stderr和看不到更新的行为的潜在混乱使得这个答案不如其他人所指出的仅仅使用一个简单的函数那么好。

使用部分只会为您保存1行代码。潜在的混乱不值得保存一行代码。

起初的

为了更简单,这里有一个使用"部分"的版本,它对包装函数有很大帮助。

1
2
3
4
5
from __future__ import print_function
import sys
from functools import partial

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

然后你就这样使用它

1
error('An error occured!')

您可以执行以下操作来检查它是否正在打印到stderr而不是stdout(从http://coreygoldberg.blogspot.com.au/2009/05/python redirect或关闭stdout和.html返回的代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
# 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方法。


同样适用于标准输出:

1
2
3
print 'spam'
sys.stdout.write('spam
'
)

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

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

  • python 3中的print()语法已经改变,因此如果需要同时支持这两个版本,则write()可能更好。


  • 我在python 3.4.3中工作。我删掉了一些显示我是怎么到这里的输入法:

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

    它起作用了吗?尝试将stderr重定向到文件,然后查看会发生什么:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [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之外(它还能去哪里?)这是有效的。


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    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
    '
    )
            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 3中,可以只使用print():

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

    几乎开箱即用:

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

    或:

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

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


    尝试:

    1
    2
    3
    4
    from sys import stderr


    print >> sys.stderr, 'spam'

    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.

    print和stderr的write函数之间的差异:stderr:stderr(标准错误)是内置于每个UNIX/Linux系统中的管道,当程序崩溃并打印出调试信息(如python中的回溯)时,它将转到stderr管道。

    print:print是一个包装器,它对输入进行格式化(输入是参数和末尾换行符之间的空格),然后调用给定对象的写入函数,默认情况下,给定对象是sys.stdout,但是我们可以传递一个文件,也就是说我们可以在文件中打印输入。

    Python 2:如果我们用的是python2,那么

    1
    2
    3
    4
    5
    6
    7
    >>> 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:

    1
    2
    3
    >>> 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.

    1
    2
    3
    4
    5
    6
    7
    8
    >>> 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

    1
    2
    3
    4
    5
    6
    7
    #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对象


    1
    2
    3
    4
    5
    6
    7
    import logging
    logging.basicConfig(format='[%(levelname)s] %(message)s')

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

    print('hello')

    PYDOC测井