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

时间:2019-05-15 07:54:00

标签: python python-3.x

根据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()

有什么作用?他们俩不应该做同一件事吗?

1 个答案:

答案 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