你能解释一下以下装饰器的工作原理:
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的代码片段(事件注册机制)。
提前谢谢
答案 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_cls
和dispatchers
参数。
所以:
set_ev_cls_dev
创建一个本地函数,并在其ev_cls
和dispatchers
参数周围返回一个闭包,并返回该函数。_switch_features_handler
作为参数调用该闭包,并通过添加callers
属性来修改并返回该参数,该属性是_Caller
对象构建的一个字符。超过dispatchers
参数并关闭了已关闭的ev_cls
参数。答案 1 :(得分:3)
在不详细说明内部发生的事情的情况下解释它是如何运作的?这种听起来像"解释没有解释,"但这是一个粗略的演练:
将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(...)
的值。
步骤1的custom_decorator
作为更传统的非参数化装饰器应用于_switch_features_handler
。