python钩子函数装饰器_在Python中实现一个钩子或回调的首选方法是什么?

I'd like to provide the capability for users of one of my modules to extend its capabilities by providing an interface to call a user's function. For example, I want to give users the capability to be notified when an instance of a class is created and given the opportunity to modify the instance before it is used.

The way I've implemented it is to declare a module-level factory function that does the instantiation:

# in mymodule.py

def factory(cls, *args, **kwargs):

return cls(*args, **kwargs)

Then when I need an instance of a class in mymodule, I do factory(cls, arg1, arg2) rather than cls(arg1, arg2).

To extend it, a programmer would write in another module a function like this:

def myFactory(cls, *args, **kwargs):

instance = myFactory.chain(cls, *args, **kwargs)

# do something with the instance here if desired

return instance

Installation of the above callback looks like this:

myFactory.chain, mymodule.factory = mymodule.factory, myFactory

This seems straightforward enough to me, but I was wondering if you, as a Python programmer, would expect a function to register a callback rather than doing it with an assignment, or if there were other methods you would expect. Does my solution seem workable, idiomatic, and clear to you?

I am looking to keep it as simple as possible; I don't think most applications will actually need to chain more than one user callback, for example (though unlimited chaining comes "for free" with the above pattern). I doubt they will need to remove callbacks or specify priorities or order. Modules like python-callbacks or PyDispatcher seem to me like overkill, especially the latter, but if there are compelling benefits to a programmer working with my module, I'm open to them.

解决方案

Combining Aaron's idea of using a decorator and Ignacio's idea of a class that maintains a list of attached callbacks, plus a concept borrowed from C#, I came up with this:

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

Decorating a function with @delegate allows other functions to be "attached" to it.

@delegate

def intfactory(num):

return int(num)

Functions can be added to the delegate with += (and removed with -=). You can also decorate with funcname.callback to add a callback function.

@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

Does this feel Pythonic?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值