Python@property致命Python错误:无法从堆栈溢出中恢复



我正在学习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

最新更新