2014-07-07 81 views
1

我在Python中遇到了一個奇怪的問題。基本上我正在試圖包裝一個函數,以便它可以創建和拆卸每個請求的遊標(不要問 - 這只是一個示例,對於展示問題非常有用!除此之外,我還有其他用途)。Python中的裝飾函數總是返回無

這裏有一個例子:

class DB(object): 
    """Our DB methods and connections""" 

    def __init__(self): 
     self.con = oursql.connect(host=host, user=user, passwd=passwd, 
            port=port, db=db) 
     self.cursor = None 

    def __del__(self): 
     self.con.close() 


def wrapper(func): 
    """Wrapper for our database methods""" 
    def _exec(*args): 
     """Wherein the wrapping takes place""" 
     db.cursor = db.con.cursor() 
     func(*args) 
     db.cursor.close() 
    return _exec 

@wrapper 
def get_tables(db): 
    """Returns a list of all tables in the database""" 
    results = [] 
    db.cursor.execute('show tables') 
    tables = db.cursor.fetchall() 
    for table in tables: 
     results.append(table[0]) 
    print results 
    return results 

if __name__ == '__main__': 
    db = DB() 
    print get_tables(db) 

這工作,但結果我得到的回報從包裝的函數只無:

[list of tables from "print results" goes in here] 
None <- returned by the "print get_tables(db)" line 
+0

'db'來自'wrapper',無論如何呢? – user2357112

+0

@ user2357112:在'if __name__'後面,'db'被指定爲全局。 –

+0

就這樣。這可能不是它應該來自哪裏的地方;它應該可能使用第一個參數而不是全局參數。 – user2357112

回答

3

你忽略了包裝的函數的返回值:

db.cursor = db.con.cursor() 
func(*args) 
db.cursor.close() 

在這裏你的函數沒有顯式的返回值,所以Python給了你相反,默認爲None

你想要捕捉的返回值,返回:

db.cursor = db.con.cursor() 
retval = func(*args) 
db.cursor.close() 
return retval 

你可以使用try:/finally這裏,以確保光標即使引發異常關閉;這簡化了代碼太如就總是執行finally套件,在try塊返回即使:

db.cursor = db.con.cursor() 
try: 
    return func(*args) 
finally: 
    db.cursor.close() 

另一種選擇是使用光標爲上下文管理器;在這種情況下,任何交易都會自動爲您承擔;在例外情況下,交易將被回滾。

with db.con.cursor() as db.cursor: 
    return func(*args) 

參見cursors as context managers的oursql文檔中:在任一情況下,光標將可以當上下文退出關閉。