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

Sco*_*ott 2 python class instance-variables

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

例如:

class Foo:
    def __init__(self):
        self.a = 1
        self.b = self.a + 1
Run Code Online (Sandbox Code Playgroud)
>>> 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
Run Code Online (Sandbox Code Playgroud)

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

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

Mad*_*ist 6

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

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

    @property
    def b(self):
        return self.a + 1
Run Code Online (Sandbox Code Playgroud)

这将创建一个只读属性b,当您以 as 访问它时,该属性的行为就像普通属性一样foo.b,但会因为它是一个描述符。它将根据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
Run Code Online (Sandbox Code Playgroud)

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