我想通过提供一个调用用户函数的接口来为我的一个模块的用户提供扩展其功能的能力。例如,我想让用户能够在创建类的实例时得到通知,并有机会在使用该实例之前对其进行修改。
我实现它的方法是声明一个执行实例化的模块级工厂函数:
# in mymodule.py def factory(cls, *args, **kwargs): return cls(*args, **kwargs)
然后,当我在mymodule中需要一个类的实例时,我会做factory(cls, arg1, arg2)而不是cls(arg1, arg2)。
factory(cls, arg1, arg2)
cls(arg1, arg2)
为了扩展它,程序员将在另一个模块中编写如下函数:
def myFactory(cls, *args, **kwargs): instance = myFactory.chain(cls, *args, **kwargs) # do something with the instance here if desired return instance
上面的回调的安装如下所示:
myFactory.chain, mymodule.factory = mymodule.factory, myFactory
这对我来说似乎很简单,但是我想知道作为Python程序员的您是否期望函数注册一个回调而不是通过赋值来完成,或者您是否期望其他方法。我的解决方案对您来说似乎可行,惯用且清晰吗?
我希望将其保持尽可能简单。我认为大多数应用程序实际上并不需要链接多个用户回调,例如(尽管在上述模式下,无限链接“免费”提供)。我怀疑他们是否需要删除回调或指定优先级或顺序。在我看来,像python- callbacks或PyDispatcher之类的模块似乎过大了,尤其是后者,但是,如果使用该模块的程序员能够获得引人注目的收益,我就可以接受。
结合了Aaron使用装饰器的想法和Ignacio的类维护维护附加回调列表的类的想法,再加上从C#借用的概念,我想到了:
class delegate(object): def __init__(self, func): self.callbacks = [] self.basefunc = func def __iadd__(self, func): if callable(func): self.__isub__(func) self.callbacks.append(func) return self def callback(self, func): if callable(func): self.__isub__(func) self.callbacks.append(func) return func def __isub__(self, func): try: self.callbacks.remove(func) except ValueError: pass return self def __call__(self, *args, **kwargs): result = self.basefunc(*args, **kwargs) for func in self.callbacks: newresult = func(result) result = result if newresult is None else newresult return result
使用修饰功能@delegate可以将其他功能“附加”到该功能。
@delegate
@delegate def intfactory(num): return int(num)
可以使用添加函数+=(使用删除-=)。您还可以装饰funcname.callback以添加回调函数。
+=
-=
funcname.callback
@intfactory.callback def notify(num): print "notify:", num def increment(num): return num+1 intfactory += increment intfactory += lambda num: num * 2 print intfactory(3) # outputs 8
这听起来像Pythonic吗?