【问题标题】:Python: to wrap functions via lambdaPython:通过 lambda 包装函数
【发布时间】:2012-03-10 00:26:58
【问题描述】:

我有一些类似的代码

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)

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

【问题讨论】:

  • 通常你使用装饰器包装函数...

标签: python wrapper decorator lambda


【解决方案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,因此不会发生递归。

使用装饰器更常见一些,但装饰器在内部会做很多相同的事情。

【讨论】:

  • 这将导致 NameError,因为没有名为 e 的变量可用。此外,这将执行函数并为其分配返回值,并且不会分配整个函数。
  • 并且没有proc(在log_event内部调用)。
  • @yak:说真的,解释一下。
【解决方案2】:

它以无限递归结束,因为当调用lambda e: log_event(handler.handle, e) 时,handler.handle 已经是 lambda 表达式。 log_event 会调用 lambdalambda 会调用 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:\Users\niklas\Desktop>foo.py
调用句柄:(EventHandler instance, 'event') {}

【讨论】:

    【解决方案3】:
    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 的方法一次(具体来说,您将获得一个将对象和底层函数对象粘合在一起的“绑定方法”对象),然后才创建匿名函数并覆盖handler.handle

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-26
      • 2017-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      • 2015-10-11
      相关资源
      最近更新 更多