我正在学习Python中的@property decorator。在一个玩具示例中,我遇到了一个我不理解的错误。
我的玩具类:
class ClassWithValidator:
def __init__(self, attribute_1):
self.attribute_1 = attribute_1
@property
def attribute_1(self):
return self.attribute_1
@attribute_1.setter
def attribute_1(self, value):
print("Setting attribute_1...")
if value < 10:
raise ValueError("attribute_1 cannot be greater or equal to 10!")
else:
self.attribute_1 = value
尝试创建其实例:
class_instance = ClassWithValidator(11)
触发以下错误:
Setting attribute_1... # repeated multiple times before the following error message:
>Fatal Python error: Cannot recover from stack overflow.
解决方法是在属性及其setter:中将self.attribute_1
替换为self._attribute_1
class FixedClassWithValidator:
def __init__(self, attribute_1):
self.attribute_1 = attribute_1
@property
def attribute_1(self):
return self._attribute_1
@attribute_1.setter
def attribute_1(self, value):
print("Setting attribute_1...")
if value < 10:
raise ValueError("attribute_1 cannot be greater or equal to 10!")
else:
self._attribute_1 = value
class_instance = FixedClassWithValidator(11)
我知道前面有下划线的属性名称(这里是_attribute_1
(意味着,按照惯例,它是私有的。然而,我仍然不明白为什么第一个代码会导致堆栈溢出。
不确定为什么会出现该错误,应该得到一个RecursionError: maximum recursion depth exceeded in comparison
。问题是setterself.attribute_1 = value
的最后一行,它在无限循环中再次调用setter。
您的第二个解决方案非常有效,但您也可以考虑使用描述符来验证数据。
class MinValidator: # Descriptor
def __init__(self, min_value):
self.min_value = min_value
def __set_name__(self, owner, name):
self.name = name
def __set__(self, obj, value):
print(f"Setting {self.name}...")
if value < self.min_value:
raise ValueError(f"attribute_1 cannot be lower than {self.min_value}!")
else:
obj.__dict__[self.name] = value
class ClassWithValidator:
attribute_1 = MinValidator(10)
def __init__(self, attribute_1):
self.attribute_1 = attribute_1