2009-12-24 49 views
14

我想記錄一個Python腳本的所有輸出。我試過了:如何在Python中重定向stderr?

import sys 

log = [] 

class writer(object): 
    def write(self, data): 
     log.append(data) 

sys.stdout = writer() 
sys.stderr = writer() 

現在,如果我「打印」某物''它會被記錄。但是,如果我舉例說一些語法錯誤,比如說「打印'某個東西#」,它不會被記錄 - 它會進入控制檯。

我該如何捕獲Python解釋器中的錯誤?

我看到一個可能的解決方案在這裏:

http://www.velocityreviews.com/forums/showpost.php?p=1868822&postcount=3

但第二個示例記錄到的/ dev/null的 - 這不是我想要的。我想登錄到像上面的例子或StringIO或類似的列表...

另外,最好我不想創建一個子進程(並在獨立的線程中讀取其stdout和stderr)。

+0

也許作家也應該實現writelines()。 不要忘記sys.stderr.flush() –

回答

5

在編譯相同代碼的過程中,您無法執行任何可以捕獲錯誤的Python代碼。它怎麼可能?如果編譯器無法完成編譯代碼,它將不會運行代碼,因此您的重定向尚未生效。

這就是你的(不受歡迎的)子進程出現的地方。你可以編寫重定向stdout的Python代碼,然後調用Python解釋器來編譯其他代碼片段。

+0

你是對的,當然它不能這樣做。對不起,這個愚蠢的問題。另一個解決方案是在另一個腳本中「執行」腳本。 – EcirH

+0

並非所有的代碼都是一次編譯的。進口報表就是一個例子。 – 2009-12-24 01:11:48

+1

另一個用例(雖然不是EcirH的):從python調用的C庫中捕獲stderr。 – 2009-12-24 01:58:11

6

我想不出一個簡單的方法。 python進程的標準錯誤比python文件對象(C vs python)低。

您可以將python腳本包裝在第二個python腳本中並使用subprocess.Popen。也有可能,你可以拉一些魔像這樣在一個腳本:

import os 
import subprocess 
import sys 

cat = subprocess.Popen("/bin/cat", stdin=subprocess.PIPE, stdout=subprocess.PIPE) 
os.close(sys.stderr.fileno()) 
os.dup2(cat.stdin.fileno(), sys.stderr.fileno()) 

然後用select.poll()定期檢查cat.stdout找到輸出。

是的,這似乎工作。

我預見到的問題是,大多數時候,python打印到stderr的東西表示它即將退出。處理這種情況的更常見方式是通過例外。

---------編輯

不知怎的,我錯過了os.pipe()函數。

import os, sys 
r, w = os.pipe() 
os.close(sys.stderr.fileno()) 
os.dup2(w, sys.stderr.fileno()) 

然後從r

18

讀我有一個軟件,我寫的工作捕獲標準錯誤到一個文件中,像這樣:

import sys 
sys.stderr = open('C:\\err.txt', 'w') 

所以它絕對有可能。

我相信你的問題是你正在創建兩個作家的實例。

也許更多的東西一樣:

import sys 

class writer(object): 
    log = [] 

    def write(self, data): 
     self.log.append(data) 

logger = writer() 
sys.stdout = logger 
sys.stderr = logger 
+0

我打算說一些關於日誌變量的內容... –

+1

如果其他代碼執行sys.stdout.flush()會怎麼樣? – Moberg

+1

在這種情況下,只需在作家類中添加一個虛擬flush方法:'def flush(self):pass' – KingRadical

0
import sys 
import tkinter 

# ******************************************** 

def mklistenconsswitch(*printf: callable) -> callable: 
    def wrapper(*fcs: callable) -> callable: 
     def newf(data): 
      [prf(data) for prf in fcs] 
     return newf 
    stdoutw, stderrw = sys.stdout.write, sys.stderr.write 
    funcs = [(wrapper(sys.stdout.write, *printf), wrapper(sys.stderr.write, *printf)), (stdoutw, stderrw)] 
    def switch(): 
     sys.stdout.write, sys.stderr.write = dummy = funcs[0] 
     funcs[0] = funcs[1] 
     funcs[1] = dummy 
    return switch 

# ******************************************** 

def datasupplier(): 
    i = 5.5 
    while i > 0: 
     yield i 
     i -= .5 

def testloop(): 
    print(supplier.__next__()) 
    svvitch() 
    root.after(500, testloop) 

root = tkinter.Tk() 
cons = tkinter.Text(root) 
cons.pack(fill='both', expand=True) 
supplier = datasupplier() 
svvitch = mklistenconsswitch(lambda text: cons.insert('end', text)) 
testloop() 
root.mainloop() 
0

其實,如果你正在使用的Linux/MAC OS,你可以使用文件重定向做到這一點。例如,如果您要運行「a.py」,並將所有將生成的消息記錄到文件「a.out」中,則它只是

python a.py 2> & 1> a。 out

相關問題