我正在寻找在实例化类后设置引用另一个实例属性的一个实例属性的最佳实践。
例如:
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。非常感谢您的协助!
答案 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
始终存在。