python类的实现中有关__settar__原理问题
具体解决思路
问题代码段:
class CustomAttributes:
def __init__(self):
self._attributes = {}
def __setattr__(self, name, value):
# 允许设置名为 '_attributes' 的属性,这是实现所必需的
if name == '_attributes':
super().__setattr__(name, value)
# 对于其他属性,添加它们到 _attributes 字典中
else:
self._attributes[name] = value
def __getattr__(self, name):
# 尝试从 _attributes 字典中获取属性
if name in self._attributes:
return self._attributes[name]
# 如果属性不存在,则调用默认的 __getattr__ 实现
else:
raise AttributeError(f"'CustomAttributes' object has no attribute '{name}'")
# 创建一个 CustomAttributes 实例
obj = CustomAttributes()
# 设置属性
obj.name = 'Alice'
obj.age = 35
# 访问属性
print(obj.name) # 输出: Alice
print(obj.age) # 输出: 35
在这段代码中,我发现特殊方法__setattr__中有段未知代码 super().__setattr__(name, value)
,我要对其功能进行一个测试。
-
在代码测试中加入_attributes的value。
import CustomAttributes obj = CustomAttributes() # 设置属性 obj.name = 'Alice' obj.age = 35 obj._attrubites = 10 # 访问属性 print(obj.name) print(obj.age) print(obj._attributes) ''' 输出: Traceback (most recent call last): File "C:\Users\GOD\Desktop\301.py", line 32, in <module> print(obj.name) ^^^^^^^^ File "C:\Users\GOD\Desktop\301.py", line 15, in __getattr__ if name in self._attributes: ^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: argument of type 'int' is not iterable '''
import CustomAttributes obj = CustomAttributes() # 设置属性 obj.name = 'Alice' obj.age = 35 obj._attributes = 10 # 访问属性 print(obj._attributes) # 输出:10
由此得知,
super().__setattr__(name, value)
这段代码的功能是使_attributes
的key可以覆盖原属性dict。 -
删掉这段代码,测试其是否为重要组成部分。
class CustomAttributes: def __init__(self): self._attributes = {} def __setattr__(self, name, value): self._attributes[name] = value def __getattr__(self, name): # 尝试从 _attributes 字典中获取属性 if name in self._attributes: return self._attributes[name] # 如果属性不存在,则调用默认的 __getattr__ 实现 else: raise AttributeError(f"'CustomAttributes' object has no attribute '{name}'") # 创建一个 CustomAttributes 实例 obj = CustomAttributes() ''' 输出: Traceback (most recent call last): File "C:\Users\GOD\Desktop\301.py", line 19, in <module> obj = CustomAttributes() ^^^^^^^^^^^^^^^^^^ File "C:\Users\GOD\Desktop\301.py", line 3, in __init__ self._attributes = {} ^^^^^^^^^^^^^^^^ File "C:\Users\GOD\Desktop\301.py", line 6, in __setattr__ self._attributes[name] = value ^^^^^^^^^^^^^^^^ File "C:\Users\GOD\Desktop\301.py", line 10, in __getattr__ if name in self._attributes: ^^^^^^^^^^^^^^^^ File "C:\Users\GOD\Desktop\301.py", line 10, in __getattr__ if name in self._attributes: ^^^^^^^^^^^^^^^^ File "C:\Users\GOD\Desktop\301.py", line 10, in __getattr__ if name in self._attributes: ^^^^^^^^^^^^^^^^ [Previous line repeated 743 more times] RecursionError: maximum recursion depth exceeded '''
由此得知,去除掉这段代码会导致触发无限递归,
当__init__
方法在创建CustomAttributes
实例时被调用时,它尝试设置_attributes
字典。这触发了__setattr__
方法的调用。
在__setattr__
方法内部,当尝试访问self._attributes
时,由于_attributes
字典尚未完全初始化,Python 会调用__getattr__
方法来获取该属性。
然后,__getattr__
方法又尝试检查name
是否在self._attributes
中,这再次触发了__getattr__
的调用,从而形成了无限递归。
总结
- 由两个实验得之:
uper().__setattr__(name, value)
允许你绕过当前类中的__setattr__
方法,并直接调用其父类的__setattr__
方法。 - 在
__init__
方法创建实例时被调用时,会调用__setattr__
方法去设置实例的属性,当在__setattr__
方法内部尝试访问,由于_attributes
字典尚未完全初始化,Python 会调用__getattr__
方法来获取该属性,从而造成递归循环。