简体   繁体   English

Python:通过lambda包装函数

[英]Python: to wrap functions via lambda

I have some code like 我有一些像

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')

that will end up with infinite recursion. 最终将导致无限递归。 While changing wrap_handler to 在将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)

the program will become OK. 该程序将变得确定。 Why is that? 这是为什么? And could anyone tell me more common ways to wrap functions? 还有谁能告诉我包装函数的更常用方法吗?

It ends in an infinite recursion as when lambda e: log_event(handler.handle, e) is called, handler.handle is already the lambda expression. 当它结束在无限递归lambda e: log_event(handler.handle, e)被调用时, handler.handle已经是λ表达式。 log_event would call the lambda and the lambda would call log_event , etc.. log_event将调用lambda ,而lambda将调用log_event等。

To fix this, just save the current method in the local-scope, this also does not need the additional lambda-expression. 要解决此问题,只需将当前方法保存在local-scope中,这也不需要额外的lambda-expression。

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')

You could also use a decorator. 您也可以使用装饰器。

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 C:\\ Users \\ niklas \\ Desktop> foo.py
Calling handle with: (EventHandler instance, 'event') {} 调用句柄的方式为:(EventHandler实例,“事件”){}

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

The anonymous function will, upon invocation, look up handler 's handle member and pass that (along with e ) to log_event . 调用时,匿名函数将查找handlerhandle成员并将其(连同e )传递给log_event Because you immediately set handler.handle to the anonymous function, the anonymous function just gets a reference to itself. 因为您立即将handler.handle设置为匿名函数,所以匿名函数仅获得对自身的引用。

This on the other hand: 另一方面:

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

Gets the handler 's method once (specifically, you get a "bound method" object gluing the object and the underlying function object together), and only then you create the anonymous function and overwrite handler.handle . 一次获取handler的方法(具体而言,您将获得一个“绑定方法”对象,将对象和基础函数对象粘合在一起),然后才创建匿名函数并覆盖handler.handle

Because functions are objects, you do not need to use a lambda to assign them to a variable. 由于函数是对象,因此不需要使用lambda即可将它们分配给变量。 Instead do: 而是:

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

In that code, you avoid evaluating handler.handle in log_event, so no recursion occurs. 在该代码中,避免在log_event中评估handler.handle,因此不会发生递归。

It's a little bit more usual to use decorators, but decorators will do much the same thing internally. 使用装饰器要平常一些,但是装饰器在内部会做很多相同的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM