我希望通过提供调用用户函数的接口,为我的一个模块的用户提供扩展其功能的功能。例如,我希望让用户能够在创建类的实例时得到通知,并在使用实例之前提供修改实例的机会。
我实现它的方式是声明一个模块级工厂函数来执行实例化:
# in mymodule.py
def factory(cls, *args, **kwargs):
return cls(*args, **kwargs)
然后,当我需要在我的模块中创建一个类的实例时,我会使用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这样的模块有点杀伤力,特别是后者,但如果使用我的模块的程序员有令人信服的好处,我对它们持开放态度。
发布于 2010-12-01 13:35:52
结合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
def intfactory(num):
return int(num)
可以使用+=
将函数添加到委托中(使用-=
将其删除)。您还可以使用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式的吗?
发布于 2010-11-30 09:11:29
让aaronsterling's idea更进一步:
class C(object):
_oncreate = []
def __new__(cls):
return reduce(lambda x, y: y(x), cls._oncreate, super(C, cls).__new__(cls))
@classmethod
def oncreate(cls, func):
cls._oncreate.append(func)
c = C()
print hasattr(c, 'spew')
@C.oncreate
def spew(obj):
obj.spew = 42
return obj
c = C()
print c.spew
发布于 2010-11-30 08:59:20
我可能会使用装饰器,这样用户就可以编写代码了。
@new_factory
def myFactory(cls, *args, **kwargs):
instance = myFactory.chain(cls, *args, **kwargs)
# do something with the instance here if desired
return instance
然后在你的模块中,
import sys
def new_factory(f):
mod = sys.modules[__name__]
f.chain = mod.factory
mod.factory = f
return f
https://stackoverflow.com/questions/4309607
复制相似问题