Python 如何在实例化类时根据另一个属性校验当前属性?
可以。在 setter 中用 self.planet_lifetime 访问另一个实例属性,并在给 species_lifetime 赋值前先初始化 planet_lifetime。
为什么初始化时会报错?
执行下面这行代码时,Python 会立即调用 species_lifetime 的 setter:
self.species_lifetime = species_lifetime
如果 setter 读取 self.planet_lifetime 时,构造函数还没有执行下一行赋值,就会触发 AttributeError。
示例代码与描述中的报错还有一个区别:如果按示例原样写成 if value > planet_lifetime:,在没有同名全局变量等外部定义的情况下,通常会触发 NameError。__init__ 的参数是该方法的局部变量,另一个方法不能直接访问。
如何修改代码?
先设置被依赖的属性,再设置需要校验的属性:
class Planet:
def __init__(self, species_lifetime, planet_lifetime):
self.planet_lifetime = planet_lifetime
self.species_lifetime = species_lifetime
@property
def species_lifetime(self):
return self._species_lifetime
@species_lifetime.setter
def species_lifetime(self, value):
if value > self.planet_lifetime:
raise ValueError(
"Species lifetime can't be longer than planet lifetime"
)
self._species_lifetime = value
这样调用 setter 时,self.planet_lifetime 已经存在。构造函数的参数顺序可以保持不变,只需调整内部赋值顺序。
使用示例:
planet = Planet(species_lifetime=80, planet_lifetime=100)
print(planet.species_lifetime) # 80
planet.species_lifetime = 90 # 允许
planet.species_lifetime = 120 # 抛出 ValueError
把名称改成 self._planet_lifetime 不会自动创建属性,仍然要先赋值才能读取。_planet_lifetime 不带 self. 时,也不是在访问实例属性。
后续修改另一个属性时怎么办?
上面的实现会在每次设置 species_lifetime 时校验,但直接修改 planet_lifetime 不会触发这个 setter。例如:
planet = Planet(80, 100)
planet.planet_lifetime = 50
此时两个属性不再满足约束。如果要求对象始终满足 species_lifetime <= planet_lifetime,还需要在 planet_lifetime 的 setter 中校验,或提供统一更新两个属性的方法,在赋值前检查整组新值。
示例假定两个值能够使用 > 比较。类型、负数或空值等限制,需要根据业务规则另行添加。
备注:内容仅供参考。
