属性和方法的 Python 装饰器?
Posted
技术标签:
【中文标题】属性和方法的 Python 装饰器?【英文标题】:Python decorator for attribute and method? 【发布时间】:2014-06-25 14:26:42 【问题描述】:如果使用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
我的直觉是我只需要像这样将 __call__ 添加到 attributeSetter
装饰器:
def __call__(self, *args, **kwargs):
self.func(*args, **kwargs)
但它不会让我使用“=”语法设置值。
为什么?
我正在共同开发 PsychoPy(心理物理学中用于刺激传递的 python 模块),我们希望在设置每个刺激参数时进行一些处理,因此装饰器避免使用 setter/getter 方法。我们默认记录每个属性更改,但在某些情况下,用户希望使用额外的 log=False 参数禁用此特定设置的记录,或提供更多参数。因此,在这些情况下,如果可以像函数/方法一样使用属性,那就太好了。
【问题讨论】:
我在后期注意到一点,您希望instance.myAttrib
既是托管值,又是可调用的 instance.myAttrib()
。恐怕你不能两者兼得。 instance.method_name
返回一个绑定方法,您可以将其存储在变量中并稍后调用。 instance.method_name()
中的()
在 属性被查找之后应用。
换句话说,无论是类还是描述符对象上的__get__
方法都不会知道您将如何处理返回的属性。这完全取决于__call__
。
感谢@MartijnPieters!我已经编辑了“类方法”。这是一个悲伤的消息,但你已经很好地解释了原因。稍后我会接受答案,这取决于在此期间是否给出了更多答案。
【参考方案1】:
您需要实现一个 __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']
中的内容)的方法;但这条路径充满了问题,因为代理对象永远无法真正成为底层属性值。
【讨论】:
以上是关于属性和方法的 Python 装饰器?的主要内容,如果未能解决你的问题,请参考以下文章
Python中的property类和@property装饰器
Python入门-6面向对象编程:06私有属性和私有方法(实现封装)-@property装饰器-get和set方法-总结