没有办法直接做到这一点。
对于实例属性,而不是类属性,您可以使用@property 轻松模拟它。每次请求时都即时计算attr2:
class Spam:
def __init__(self, a):
self.a = a
@property
def twoa(self):
return 2*self.a
(如果计算成本很高,可能会添加缓存),或者每当有人修改attr1时重新计算attr2:
class Spam:
def __init__(self, a):
self.a = a
@property
def a(self):
return self._a
@a.setter
def a(self):
self._a = a
self.twoa = 2*a
这只是因为property 创建了一个描述符,您存储在类对象中,而不是实例中,所以当有人查找twoa(在第一个示例中)或a(在第二个示例中)时Spam 实例,它回退到查找类上的描述符。
如果您希望类属性的第一个属性,它在查找实例值时按原样工作,而不是在类本身上(不幸的是,这就是您在示例中所做的)。
如果你需要第二个,它根本不起作用。
例如:
>>> class Spam:
... a = 10
... @property
... def twoa(self):
... return 2*self.a
>>> spam = Spam()
>>> spam.twoa
20
>>> Spam.twoa
<property at 0x12345678>
>>> class Eggs(Spam):
... a = 5
>>> eggs = Eggs()
>>> eggs.twoa
10
>>> Eggs.twoa
<property at 0x12345678>
如果这不是问题,那就太好了。但如果是,则需要将描述符放在类的类上——即元类:
class MetaSpam(type):
@property
def twoa(cls):
return 2 * cls.a
class Spam(metaclass=MetaSpam):
a = 2
class Eggs(Spam):
a = 3
对于像twoa(或你的attr2)这样的简单案例,拖入一个元类是可怕的矫枉过正。
但如果您很有可能已经在拖入自定义元类,例如复杂的表单和字段系统,那么它可能是合适的。