python 装饰器实现事件绑定_属性和方法的Python装饰器?

Is it possible to have a decorator that makes a method work like an attribute if values are assigned to it using class.something = 2 and work like a method if it is called like class.something(2, True)?

What I currently have

To be more concrete, I currently have the following

class attributeSetter(object):

''' Makes functions appear as attributes. Takes care of autologging.'''

def __init__(self, func):

self.func = func

def __set__(self, obj, value):

return self.func(obj, value)

def __repr__(self):

return repr(self.__getattribute__)

So with this class with a decorated method:

class myClass(object):

@attributeSetter # decorated!

def myAttrib(self, value, add=False, subtract=False):

if add:

value += 2

if subtract:

value -= 2

self.__dict__['myAttrib'] = value

I can do this:

instance = myClass()

instance.myAttrib = 2 # sets the value to 2

instance.myAttrib *= 4 # now 8

print instance.myAttrib # 8

What I want

But I want, in addition, to be able to do this:

instance.myAttrib(3, add=True) # now 8 + 3 + 2 = 13

instance.myAttrib(0, subtact=True) # now 13 + 0 - 2 = 11

print instance.myAttrib # 11

My hunch is that I just have to add a __call__ to the attributeSetter decorator like this:

def __call__(self, *args, **kwargs):

self.func(*args, **kwargs)

but then it won't let me set values using the "=" syntax.

Why?

I'm co-developing PsychoPy (a python module for stimulus delivery in psychphysics) and we want do to some processing when each stimulus parameter is set, hence the decorator to avoid setter/getter methods. We log each attribute change by default but in some cases, users want to disable logging of this particular setting with an extra log=False argument, or provide more arguments. Hence it would be nice in those cases if could just use the attribute like a function/method, which it really is in the first place.

解决方案

You'll need to implement a __get__ method returning a callable; your decorator already provides a descriptor object, simply make it work when accessing as an attribute.

This can be as simple as turning around and binding the wrapped function (so you get a bound method):

class attributeSetter(object):

''' Makes functions appear as attributes. Takes care of autologging.'''

def __init__(self, func):

self.func = func

def __get__(self, instance, owner):

return self.func.__get__(instance, owner)

def __set__(self, obj, value):

return self.func(obj, value)

However, this makes it incompatible with simply accessing the attribute! instance.myAttrib now returns a bound method! You cannot have it both ways here; methods are simply bound attributes (so attributes that passed through the descriptor protocol), that happen to be callable.

You could of course return a proxy object from __get__; one that implements a __call__ method and otherwise tries to act as much as possible as the underlying managed instance attribute (what your function stored in self.__dict__['myAttrib']); but this path is fraught with problems as a proxy object can never truly be the underlying attribute value.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值