假设我有一个看起来像这样的类(class):
class Test(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = self.a + self.b
我要
self.c
的值每当属性值改变时self.a
或 self.b
同一个实例的变化。例如
test1 = Test(2,4)
print test1.c # prints 6
test1.a = 3
print test1.c # prints = 6
我知道为什么它仍然会打印 6,但是有没有一种机制可以用来触发对
self.c
的更新当self.a
已经改变。或者我唯一的选择是有一个方法可以返回 self.c
的值。基于 self.a
的当前状态和 self.b
最佳答案
就在这里!这叫做属性。
只读属性
class Test(object):
def __init__(self,a,b):
self.a = a
self.b = b
@property
def c(self):
return self.a + self.b
通过上面的代码,
c
现在是 Test
类的只读属性。可变属性
你也可以给一个属性一个 setter,这将使它读/写并允许你直接设置它的值。它看起来像这样:
class Test(object):
def __init__(self, c = SomeDefaultValue):
self._c = SomeDefaultValue
@property
def c(self):
return self._c
@c.setter
def c(self,value):
self._c = value
但是,在这种情况下,为
self.c
设置 setter 是没有意义的,因为它的值取决于 self.a
和 self.b
。@property 是什么意思?
@property
位是装饰器的一个例子。装饰器实际上将它装饰的函数(或类)包装到另一个函数(装饰器函数)中。在函数被装饰之后,当它被调用时,实际上是装饰器以函数(及其参数)作为参数被调用。通常(但不总是!)装饰函数会做一些有趣的事情,然后像往常一样调用原始(装饰)函数。例如:def my_decorator(thedecoratedfunction):
def wrapped(*allofthearguments):
print("This function has been decorated!") #something interesting
thedecoratedfunction(*allofthearguments) #calls the function as normal
return wrapped
@my_decorator
def myfunction(arg1, arg2):
pass
这相当于:
def myfunction(arg1, arg2):
pass
myfunction = my_decorator(myfunction)
所以这意味着在上面的类示例中,您也可以这样做,而不是使用装饰器:
def c(self):
return self.a + self.b
c = property(c)
它们是完全一样的东西。
@property
只是一种语法糖,用属性 getter 和 setter(删除器也是一个选项)替换对 myobject.c
的调用。等等 - 这是如何工作的?
您可能想知道为什么只执行一次:
myfunction = my_decorator(myfunction)
...导致如此剧烈的变化!因此,从现在开始,在调用时:
myfunction(arg1, arg2)
...您实际上是在调用
my_decorator(myfunction)
,将 arg1, arg2
发送到 wrapped
内部的内部 my_decorator
函数。不仅如此,即使您在函数调用中根本没有提到 my_decorator
或 wrapped
,所有这些都会发生!所有这些都通过称为闭包的东西起作用。当函数以这种方式传递给装饰器时(例如
property(c)
),函数的名称被重新绑定(bind)到函数的包装版本而不是原始函数,并且原始函数的参数总是传递给 wrapped
而不是原来的功能。这就是闭包的工作方式,并没有什么神奇之处。 Here is some more information about closures。描述符
到目前为止总结一下:
@property
只是将类方法包装在 property()
函数内部的一种方式,因此调用包装的类方法而不是原始的未包装的类方法。 但是属性函数是什么? 它有什么作用?属性函数向类添加称为描述符的东西。简而言之,描述符是一个对象类,可以具有单独的 get、set 和 delete 方法。当你这样做时:
@property
def c(self):
return self._c
...您正在向名为
Test
的 c
类添加一个描述符,并将 __get__()
描述符的 get 方法(实际上是 c
)定义为等于 c(self)
方法。当你这样做时:
@c.setter
def c(self,value):
self._c
...您正在将
__set__()
描述符的 set 方法(实际上是 c
)定义为等于 c(self,value)
方法。概括
只需将
@property
添加到您的 def c(self)
方法即可完成大量的工作!在实践中,您可能不需要立即理解所有这些就可以开始使用它。但是,我建议您记住,当您使用 @property
时,您正在使用装饰器、闭包和描述符,如果您真的很想学习 Python,那么花时间单独研究这些主题中的每一个都非常值得。
关于python - 动态更新依赖于同一对象其他属性状态的对象属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27571546/