2009-12-31 25 views
3

如果我有一個包含大量打印語句的函數:Python封裝函數以打印到變量

ie。

def funA(): 
    print "Hi" 
    print "There" 
    print "Friend" 
    print "!" 

我想要做的就是這樣的事情

def main(): 
    ##funA() does not print to screen here 
    a = getPrint(funA()) ##where getPrint is some made up function/object 
    print a ##prints what funA would normally print at this step 

所以當FuncA的被稱爲它不會做任何印刷,而是輸出到一個目標。然後我打印對象以獲得結果。有沒有辦法做到這一點?我也不想觸摸原始功能。

我希望它是有道理的。

+3

相關:http:// stackoverflow。com/questions/1218933/can-i-redirect-the-stdout-in-python-into-some-sort-of-string-buffer – jldupont

回答

7

你可以做幾乎正是你想要的,只要你不介意一個小小的語法差別:

import cStringIO 
import sys 

def getPrint(thefun, *a, **k): 
    savstdout = sys.stdout 
    sys.stdout = cStringIO.StringIO() 
    try: 
    thefun(*a, **k) 
    finally: 
    v = sys.stdout.getvalue() 
    sys.stdout = savstdout 
    return v 

微小的區別是,你必須調用getPrint(funA)getPrint(funA()) - 即你必須通過功能對象本身,沒有尾隨括號,這將立即稱它,之前getPrint可以做到它的魔力。

如果你絕對堅持對這些額外的括號,然後getPrint不能做所有所需的準備,必須由其他代碼來補充準備的東西吧(我強烈建議失去了額外的括號,從而使所有的封裝getPrint!中的功能)。

+0

+1。我將使用sys .__ stdout__,它正式包含原始的sys.stdout。如果我沒有弄錯,沒有必要將原始的sys.stdout保存在savstdout中。 – EOL

+0

@EOL,如果您在IDLE或其他基於GUI的IDE下運行您的代碼,則「原始標準輸出」可能無用或不可用(例如,它可能關閉,指向不存在的終端等);並且確實需要保存和恢復'sys.stdout',以便在getPrint不存在時將IDE恢復爲可用狀態。 –

+1

你爲什麼要調用cStringIO模塊? – 2010-10-04 04:35:41

1

使用cStringIO(請參閱doc)。

from cStringIO import StringIO 

old_stdout = sys.stdout 
sys.stdout = mystdout = StringIO() 

getPrint(funA()) 
# use mystdout to get string 
3
from cStringIO import StringIO 

def getPrint(func, *args, **kwds): 
    old_stdout = sys.stdout 
    sys.stdout = StringIO() 
    try: 
    func(*args, **kwds) 
    except: 
    raise 
    else: 
    return sys.stdout.getvalue() 
    finally: 
    sys.stdout = old_stdout 

#... 
a = getPrint(funA) # notice no(), it is called by getPrint 
print a.rstrip("\n") # avoid extra trailing lines 
2

最好的辦法是做一個上下文管理

from contextlib import contextmanager 
import StringIO 
import sys 

@contextmanager 
def capture(): 
    old_stdout = sys.stdout 
    sys.stdout = StringIO.StringIO() 
    try: 
     yield sys.stdout 
    finally: 
     sys.stdout = old_stdout 

現在你可以運行任何打印代碼:後來

with capture() as c: 
    funA() 
    funB() 
    print 'HELLO!' 

則:

print c.getvalue() 
+0

您可以像別人指出的那樣使用cStringIO。 – nosklo

0

最簡單的事情是改變你的funA()不打印任何內容,只是簡單地返回字符串值。

像這樣:

def funA(): 
    return "Hi\n" + "There\n" + "Friend\n" + "!\n" 

# later: 
print(funA()) 

它總是容易收集字符串,並打印出來;在打印字符串時收集字符串更容易。

如果你有大量現有的打印功能,那麼是的,使用這裏提供的技巧之一來收集輸出。

+0

問題在於,我發佈的函數並不是微不足道的。它要求其他功能調用其他打印功能。 –

+0

那麼,你有兩個選擇。如果所有的函數都使用一個公共的單一函數來發出他們的輸出,那麼勾住這個函數就可以捕獲所有的輸出;否則(也許他們都使用Python 2.x打印*聲明*,你不能真正掛鉤),那麼你會想使用這個頁面上記錄的技巧之一。 – steveha