Python:通过lambda包装函数

Python:通过lambda包装函数,python,wrapper,decorator,lambda,Python,Wrapper,Decorator,Lambda,我有一些代码,比如 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

我有一些代码,比如

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')
这将以无限递归结束。将
包装处理程序
更改为

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)

程序将变得正常。为什么呢?还有谁能告诉我更常见的包装函数的方法吗?

因为函数是对象,所以不需要使用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_事件中计算handler.handle,因此不会发生递归


使用decorator更为常见,但decorator在内部也会做同样的事情。

因为函数是对象,所以不需要使用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_事件中计算handler.handle,因此不会发生递归


使用decorator更为常见,但decorator在内部也会做同样的事情。

它以无限递归结束,就像调用
lambda e:log\u事件(handler.handle,e)
时,
handler.handle
已经是lambda表达式一样
log\u event
将调用lambda,lambda将调用
log\u 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:\Users\niklas\Desktop>foo.py
使用:(EventHandler实例,'event'){}调用句柄


当调用
lambda e:log_事件(handler.handle,e)
时,
handler.handle
已经是lambda表达式,它以无限递归结束
log\u event
将调用lambda,lambda将调用
log\u 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:\Users\niklas\Desktop>foo.py
使用:(EventHandler实例,'event'){}调用句柄

在调用时,匿名函数将查找
处理程序
句柄
成员,并将其(连同
e
)传递给
日志事件
。因为您立即将
handler.handle
设置为匿名函数,所以匿名函数只获取对自身的引用

另一方面:

handle_func = handler.handle
handler.handle = lambda e: log_event(handle_func, e)
获取
处理程序的方法一次(具体地说,您将得到一个“绑定方法”对象,将对象和基础函数对象粘合在一起),然后才创建匿名函数并覆盖
处理程序.handle

在调用时,匿名函数将查找
处理程序
句柄
成员,并将其(连同
e
)传递给
日志事件
。因为您立即将
handler.handle
设置为匿名函数,所以匿名函数只获取对自身的引用

另一方面:

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

获取
处理程序的方法一次(具体地说,是一个将对象和底层函数对象粘合在一起的“绑定方法”对象),只有这样,您才能创建匿名函数并覆盖
处理程序.handle

通常使用decorator包装函数…通常使用decorator包装函数…这将导致名称错误,因为没有名为
e
的变量可用。此外,这将执行函数并分配其返回值,而不会分配整个函数。并且没有
proc
(在
log\u事件中调用)
。@yak:认真地说,请解释一下。这将导致名称错误,因为没有名为
e
的变量可用。此外,这将执行函数并分配其返回值,而不会分配整个函数。而且没有
proc
(在
log\u事件中调用)
。@yak:认真地说,请解释一下。