一个实例属性引用另一个实例属性,并在类实例化后进行更新

时间:2020-01-02 20:59:12

标签: python class instance-variables

我正在寻找在实例化类后设置引用另一个实例属性的一个实例属性的最佳实践。

例如:

class Foo:
    def __init__(self):
        self.a = 1
        self.b = self.a + 1
>>> obj_foo = Foo()
>>> obj_foo.a
1
>>> obj_foo.b
2
>>> obj_foo.a = 5
>>> obj_foo.a
5
>>> obj_foo.b
2 # I want this to be 6

一个实例属性引用另一个实例是不好的做法吗?

我可以看到如何实现一种方法来检查和更新依赖的实例属性,但是这似乎有很多开销/ hacky。非常感谢您的协助!

1 个答案:

答案 0 :(得分:5)

似乎您实际上根本不需要存储b的值,而是想根据a的值动态生成它。幸运的是,有一个property类/装饰器可以用于此目的:

class Foo:
    def __init__(self, a=1):
        self.a = a

    @property
    def b(self):
        return self.a + 1

这将创建一个只读属性b,当您以foo.b的身份访问该属性时,其行为将与普通属性一样,但是会因为它是descriptor而起作用。它将根据设置为foo.a的值重新计算值。

您对每次调用方法进行计算的担心并非完全没有道理。使用.运算符已经执行了一些相当昂贵的查找,因此您的玩具盒如上所示很好。但是,您经常会遇到一些情况,这些情况所需要的不仅仅是在参数上加上1。在这种情况下,您将需要使用诸如缓存之类的方法来加快处理速度。例如,您可以将a设置为可设置的属性。每当a的值更新时,您都可以通过某种方式“使” b“无效”,例如设置标志,或仅将None分配给缓存的值。现在,您的昂贵计算仅在必要时运行:

class Foo:
    def __init__(self, a=1):
        self._a = a

    @property
    def a(self):
        return self._a

    @a.setter
    def a(self, value):
        self._a = value
        self._b = None

    @property
    def b(self):
        if self._b is None:
            # Placeholder for expensive computation here
            self._b = self._a + 1
        return self._b

在此示例中,在self.a = a中设置__init__将触发属性foo.a的设置器,确保属性foo._b始终存在。