Python装饰器的属性和方法?

时间:2014-05-08 09:20:01

标签: python methods attributes decorator python-decorators

如果使用class.something = 2为其分配值,并且如果像class.something(2, True)那样调用方法,那么是否可以使装饰器使方法像属性一样工作?

我目前拥有什么

更具体一点,我目前有以下

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__)

所以这个类有一个装饰方法:

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

我可以这样做:

instance = myClass()
instance.myAttrib = 2  # sets the value to 2
instance.myAttrib *= 4  # now 8
print instance.myAttrib  # 8

我想要什么

但是,我希望能够做到这一点:

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

我的预感是,我只需要向attributeSetter装饰器添加 __ call __ ,如下所示:

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

然后它不会让我使用" ="设置值。语法。

为什么?

我正在共同开发PsychoPy(一种用于心理学中的刺激传递的python模块),我们希望在设置每个刺激参数时进行一些处理,因此装饰者可以避免使用setter / getter方法。我们默认记录每个属性更改,但在某些情况下,用户希望使用额外的log = False参数禁用此特定设置的记录,或提供更多参数。因此,如果可以像使用函数/方法一样使用属性,那将是很好的,它实际上是首先。

1 个答案:

答案 0 :(得分:3)

你需要实现一个__get__ 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)

然而,这使得它与仅访问该属性不兼容! instance.myAttrib现在返回一个绑定方法!你不能在这里双管齐下;方法只是绑定属性(因此通过描述符协议传递的属性)恰好是可调用的。

您当然可以从__get__返回代理对象;一个实现__call__方法的方法,并尝试尽可能多地作为底层托管实例属性(您的函数存储在self.__dict__['myAttrib']中);但是这条路径充满了问题,因为代理对象永远不会真正 基础属性值。