我有一些像
这样的代码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)
程序将变好。这是为什么?谁能告诉我更常用的功能包装方法呢?
答案 0 :(得分:7)
它以无限递归结束,因为调用lambda e: log_event(handler.handle, e)
时,handler.handle
已经是 lambda 表达式。 log_event
会调用 lambda 而 lambda 会调用log_event
等等。
要解决此问题,只需将当前方法保存在本地范围内,这也不需要额外的lambda表达式。
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:\用户\尼古拉斯\桌面和GT; foo.py
调用句柄:( EventHandler实例,'event'){}
答案 1 :(得分:2)
handler.handle = lambda e: log_event(handler.handle, e)
匿名函数将在调用时查找handler
的{{1}}成员并将其(以及handle
)传递给e
。因为您立即将log_event
设置为匿名函数,所以匿名函数只会获取对自身的引用。
另一方面:
handler.handle
获取handle_func = handler.handle
handler.handle = lambda e: log_event(handle_func, e)
的方法一次(具体来说,你得到一个“绑定方法”对象粘合对象和底层函数对象),然后你才创建匿名函数并覆盖{{1} }。
答案 2 :(得分: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,因此不会发生递归。
使用装饰器会更常见,但装饰器会在内部做同样的事情。