为什么 setattr(super(), ...) 不等于 super().__setattr__(...)?

Max*_*xpm 8 python python-3.x

根据这个答案

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()
Run Code Online (Sandbox Code Playgroud)

是什么赋予了?他们不应该做同样的事情吗?

use*_*ica 4

您链接到的答案掩盖了一些重要的细节。长话短说,setattr绕过了的魔力,因此它尝试在代理对象本身而不是 上super设置属性。super()self


setattr(a, b, c)不是 的语法糖a.__setattr__(b, c)。和常规属性分配都通过直接搜索对象类型的方法解析顺序(类和所有超类的精心排序的列表)来setattr查找方法,绕过实例 dict 和/钩子。__setattr____getattribute____getattr__

相反,a.__setattr__(b, c)仅对 执行常规属性查找__setattr__,因此它会遍历__getattribute____getattr__,并检查实例字典,除非__getattribute__另有说明。


super实现一个自定义__getattribute__方法来发挥其属性魔法。super().__setattr__使用此钩子,查找C的超类__setattr__并进行绑定self,从而生成用于设置 的属性的方法对象self

setattr(super(), ...)绕过__getattribute__. 它执行前面提到的直接MRO搜索,搜索super整个MRO,得到一个用于在超级实例本身上设置属性的方法对象。该super实例没有 来__dict__存储任意属性数据,因此尝试设置foo属性会失败并显示TypeError.