2012-02-19 64 views
0

包裝功能我有一些這樣的代碼的Python:通過拉姆達

class EventHandler: 
    def handle(self, event): 
     pass 

def wrap_handler(handler): 
    def log_event(proc, e): 
     print e 
     proc(e) 
    handler.handle = lambda e: log_event(handler.handle, e) 

handler = EventHandler() 
wrap_handler(handler) 
handler.handle('event') 

將結束了無限遞歸。同時將wrap_handler更改爲

def wrap_handler(handler): 
    def log_event(proc, e): 
     print e 
     proc(e) 
    # handler.handle = lambda e: log_event(handler.handle, e) 
    handle_func = handler.handle 
    handler.handle = lambda e: log_event(handle_func, e) 

程序將變爲OK。這是爲什麼?誰能告訴我更常用的方法來包裝功能?

+2

通常你使用裝飾器包裝函數... – Gandaro 2012-02-19 09:17:35

回答

7

它在無限遞歸中結束,因爲當調用lambda e: log_event(handler.handle, e)時,handler.handle已經是lambda表達式。 log_event會召喚拉姆達拉姆達會打電話log_event等。

爲了解決這個問題,只需保存當前的方法在局部範圍,這也並不需要額外的λ-表達。

class EventHandler: 
    def handle(self, event): 
     pass 

def wrap_handler(handler): 
    proc = handler.handle 
    def log_event(e): 
     print e 
     proc(e) 
    handler.handle = log_event 

handler = EventHandler() 
wrap_handler(handler) 
handler.handle('event') 

您還可以使用裝飾器。

def logging(function): 
    def wrapper(*args, **kwargs): 
     print "Calling %s with:" % function.__name__, args, kwargs 
     return function(*args, **kwargs) 
    return wrapper 

class EventHandler: 
    @ logging 
    def handle(self, event): 
     pass 

    def __repr__(self): 
     return "EventHandler instance" 

handler = EventHandler() 
handler.handle('event') 

C:\用戶\尼古拉斯\桌面> foo.py
調用句柄與:(事件處理程序的實例, '事件'){}

1

因爲函數是對象,所以不需要使用lambda將它們分配給變量。相反,這樣做:

def wrap_handler(handler): 
    proc = handler.handle 
    def log_event(e): 
     print e 
     proc(e) 
    # handler.handle = lambda e: log_event(handler.handle, e) 
    handler.handle = log_event 

在該代碼中,你避免在評估log_event handler.handle,所以沒有發生遞歸。

使用裝飾器是比較平常的事情,但裝飾器在內部會做很多相同的事情。

+1

這將導致一個* NameError *,因爲沒有名爲'e'的變量可用。此外,這將執行該函數並分配它的返回值,並且它不會分配整個函數。 – 2012-02-19 09:27:18

+0

並沒有'proc'(在'log_event'內部調用)。 – yak 2012-02-19 12:15:27

+0

@ yak:是的。 – Marcin 2012-02-19 13:00:00

2
handler.handle = lambda e: log_event(handler.handle, e) 

匿名功能將,在調用後,查找handlerhandle成員,並將其(與e一起)傳遞給log_event。因爲您立即將handler.handle設置爲匿名函數,匿名函數僅獲取對自身的引用。

這在另一方面:

handle_func = handler.handle 
handler.handle = lambda e: log_event(handle_func, e) 

獲取handler「s法一次(具體而言,會得到一個‘結合方法’對象膠粘對象和底層函數對象一起),才把你創建匿名功能並覆蓋handler.handle