装饰员与参数

时间:2014-11-17 20:25:12

标签: python decorator python-decorators

你能解释一下以下装饰器的工作原理:

def set_ev_cls(ev_cls, dispatchers=None):
    def _set_ev_cls_dec(handler):
        if 'callers' not in dir(handler):
            handler.callers = {}
        for e in _listify(ev_cls):
            handler.callers[e] = _Caller(_listify(dispatchers), e.__module__)
        return handler
    return _set_ev_cls_dec


@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def _switch_features_handler(self, ev):
    datapath = ev.msg.datapath
    ....

请不要详细了解该功能内部的内容。我对如何使用参数包装方法的装饰器感兴趣。顺便说一句,它是Ryu的代码片段(事件注册机制)。

提前谢谢

2 个答案:

答案 0 :(得分:4)

首先,装饰器只是一个用函数调用的函数。特别是,以下是(几乎)相同的事情:

@spam
def eggs(arg): pass

def eggs(arg): pass
eggs = spam(eggs)

那么,当装饰器接受参数时会发生什么?同样的事情:

@spam(arg2)
def eggs(arg): pass

def eggs(arg): pass
eggs = spam(arg2)(eggs)

现在,请注意最终返回并用于代替_set_ev_cls_dec的函数_switch_features_handler是在装饰器内定义的本地函数。这意味着它可以是来自外部函数的变量的闭包 - 包括外部函数的参数。因此,它可以在调用时使用handler参数,以及它在装饰时获得的ev_clsdispatchers参数。

所以:

  • set_ev_cls_dev创建一个本地函数,并在其ev_clsdispatchers参数周围返回一个闭包,并返回该函数。
  • _switch_features_handler作为参数调用该闭包,并通过添加callers属性来修改并返回该参数,该属性是_Caller对象构建的一个字符。超过dispatchers参数并关闭了已关闭的ev_cls参数。

答案 1 :(得分:3)

在不详细说明内部发生的事情的情况下解释它是如何运作的?这种听起来像"解释没有解释,"但这是一个粗略的演练:

  1. set_ev_cls视为装饰工厂。它是在调用装饰器时捕获参数的:

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    

    返回一个函数_set_ev_cls_dec,其变量绑定到:

    ev_cls = ofp_event.EventOFPSwitchFeatures
    dispatchers = CONFIG_DISPATCHER
    

    或换句话说,你现在有一个定制的'或者'参数化'调度员在逻辑上等同于:

    def custom_decorator(handler):
        if 'callers' not in dir(handler):
            handler.callers = {}
        for e in _listify(ofp_event.EventOFPSwitchFeatures):
            handler.callers[e] = _Caller(_listify(CONFIG_DISPATCHER), e.__module__)
        return handler
    

    (如果您在调用ofp_event.EventOFPSwitchFeatures时捕获了CONFIG_DISPATCHER@set_ev_cls(...)的值。

  2. 步骤1的custom_decorator作为更传统的非参数化装饰器应用于_switch_features_handler