首页 > 解决方案 > 一个实例属性引用另一个,在类实例化后更新

问题描述

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

例如:

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。非常感谢任何帮助!

标签: pythonclassinstance-variables

解决方案


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

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

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

这将创建一个只读属性b,当您访问它时,它的行为就像普通属性一样foo.b,但会 a 因为它是一个描述符。它将根据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 = ain__init__将触发 property 的 setter foo.a,确保该属性foo._b始终存在。


推荐阅读