根据this answer:
setattr(instance, name, value)
是instance.__setattr__(name, value)
的语法糖
但是:
class C:
def __init__(self):
# OK.
super().__setattr__("foo", 123)
# AttributeError: 'super' object has no attribute 'foo'
setattr(super(), "foo", 123)
c = C()
有什么作用?他们俩不应该做同一件事吗?
答案 0 :(得分:3)
您链接的答案掩盖了一些重要的细节。长话短说,setattr
绕过了super
的魔力,因此它尝试在super()
代理对象本身而不是self
上设置属性。
setattr(a, b, c)
不是a.__setattr__(b, c)
的语法糖。 setattr
和常规属性分配都通过直接搜索对象类型的method resolution order(类和所有超类的精心排序的列表)来寻找__setattr__
方法,而绕过实例dict和__getattribute__
/ __getattr__
钩子。
相比之下,a.__setattr__(b, c)
只是对__setattr__
执行常规属性查找,因此它经过__getattribute__
和__getattr__
,并且它检查实例字典,除非{{1 }}说不。
__getattribute__
实现了自定义的super
方法来实现其神奇的属性。 __getattribute__
使用此钩子,找到super().__setattr__
的超类的C
并绑定__setattr__
,从而得到用于在self
上设置属性的方法对象。
self
绕过setattr(super(), ...)
。它执行前面提到的直接MRO搜索,搜索__getattribute__
的MRO,从而生成用于在超级实例本身上设置属性的方法对象。 super
实例没有super
来存储任意属性数据,因此尝试设置__dict__
属性会失败,并显示foo
。