簡體   English   中英

如何在 Python 中打印到 stderr?

[英]How to print to stderr in Python?

有幾種方法可以寫入 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)

這些方法之間有什么區別? 應該首選哪種方法?

我發現這是唯一一個簡短、靈活、便攜和可讀的:

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

可選功能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。 列表理解是不經常使用的“大事”(可讀性)。

蟒蛇2:

print >> sys.stderr, "fatal error"

蟒蛇 3:

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

長答案

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 error\n")

看起來更面向對象,並且優雅地從通用到特定。 但請注意, 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將包含打印在標准輸出上的“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 並且沒有看到行為更新的潛在混淆使得這個答案不如其他人指出的那樣僅僅使用簡單的函數。

使用 partial 只會為您節省 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 ):

# 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('spam\n')

如其他答案所述, print提供了一個漂亮的界面,通常更方便(例如,用於打印調試信息),而write更快,並且當您必須以某種方式精確格式化輸出時也更方便。 我也會考慮可維護性:

  1. 您稍后可能會決定在 stdout/stderr 和常規文件之間切換。

  2. Python 3 中的print()語法發生了變化,因此如果您需要同時支持這兩個版本, 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('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倍!

另一種方式

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

問題的答案是:在 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 尾隨逗號在 Python3 中已成為參數,因此如果我們使用尾隨逗號來避免打印后的換行符,這在 Python3 中將看起來像 print('Text to print', end=' ') ,這是 Python2 下的語法錯誤.

http://python3porting.com/noconv.html

如果我們在 python3 中檢查上述相同的情況:

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

在 Python 2.6 下有一個未來的導入來將 print 變成一個函數。 因此,為了避免任何語法錯誤和其他差異,我們應該從將來導入 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 是一個包裝器,它在最后用空格和換行符包裝輸入,並使用 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

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

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

print('hello')

pydoc日志記錄

我這樣做只是為了好玩,但這是另一種方式...... :-)

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