python - 动态更新依赖于同一对象其他属性状态的对象属性

标签 python

假设我有一个看起来像这样的类(class):

class Test(object):
   def __init__(self, a, b):
      self.a = a
      self.b = b
      self.c = self.a + self.b 

我要self.c的值每当属性值改变时self.aself.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.aself.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_decoratorwrapped,所有这些都会发生!

所有这些都通过称为闭包的东西起作用。当函数以这种方式传递给装饰器时(例如 property(c) ),函数的名称被重新绑定(bind)到函数的包装版本而不是原始函数,并且原始函数的参数总是传递给 wrapped 而不是原来的功能。这就是闭包的工作方式,并没有什么神奇之处。 Here is some more information about closures

描述符

到目前为止总结一下:@property 只是将类方法包装在 property() 函数内部的一种方式,因此调用包装的类方法而不是原始的未包装的类方法。 但是属性函数是什么? 它有什么作用?

属性函数向类添加称为描述符的东西。简而言之,描述符是一个对象类,可以具有单独的 get、set 和 delete 方法。当你这样做时:
@property
def c(self):
    return self._c

...您正在向名为 Testc 类添加一个描述符,并将 __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/

相关文章:

python - 泛型、类和实例

python - 哪里可以找到 2020 年 NFL XML 赛程数据

python - 可能替换的所有版本

python - 如何对验证日期时间是否为特定 ISO 格式的函数进行单元测试?

python - HTML 解析,lxml、python、.tail 被 <br> 标签分解

python - 更改子类 `ndarray` 就地 View

Python os.write(文件处理程序,数据): TypeError An Integer Required

python - Django haystack 继承问题

python - 将多个文件中的所有列合并为一个(在一行中!)

python - Docplex 添加约束太慢