Python 为什么调用super().foo和super()之间有区别

Python 为什么调用super().foo和super()之间有区别,python,python-3.x,super,Python,Python 3.x,Super,我原以为super()总是尝试在基类中使用方法(或属性)运行,直到遇到一个用例,它使用super()获取子类的属性。简化代码如下所示 class Base: value = "base" def foo(self): print(f"Base foo, {self.value}") class Derived(Base): value = "derived" def foo(self

我原以为super()总是尝试在基类中使用方法(或属性)运行,直到遇到一个用例,它使用
super()获取子类的属性。简化代码如下所示

class Base:
    value = "base"

    def foo(self):
        print(f"Base foo, {self.value}")

class Derived(Base):
    value = "derived"

    def foo(self):
        print(f"Derived foo, {self.value}")


    def bar(self):
        print(f"Derived bar {self.value}")
        print(super().value)
        print(super().__getattribute__("value"))
        super().foo()
        super().__getattribute__('foo')()

d = Derived()
d.bar()
输出

Derived bar derived
base
derived
Base foo, derived
Derived foo, derived
这有点超出了我之前的理解,只是
\uuu getattribute\uu
是一个例外吗?我不能得到任何进一步的细节与此,希望任何人都可以帮助我更清楚地理解这一点,谢谢


编辑以遵循
\uuuu getattribute\uuuu
问题,如下所示:

class Base:
    value = "base"

    def foo(self):
        print(f"Base foo, {self.value}")


    def __getattribute__(self, k):
        print(f"Base get attr {self}, {k}")
        return super().__getattribute__(k)


class Derived(Base):
    value = "derived"

    def foo(self):
        print(f"Derived foo, {self.value}")


    def __getattribute__(self, k):
        print(f"Derived get attr {self}, {k}")
        return super().__getattribute__(k)


    def bar(self):
        print("Derived bar")
        print(super().value)
        print(super().__getattribute__("value"))

d = Derived()
d.bar()
输出为:

Derived get attr <__main__.Derived object at 0x7fb0621dba90>, bar
Base get attr <__main__.Derived object at 0x7fb0621dba90>, bar
Derived bar
base
Base get attr <__main__.Derived object at 0x7fb0621dba90>, value
derived
Derived get attr,bar
基本属性
导杆
基础
基本获取属性,值
衍生

更具体地说,
super
在查找某些属性/方法时基本上跳过了当前类。在单继承的情况下,这相当于查找基类。这总是发生在上面

In [38]: class Base:
    ...:     value = "base"
    ...:
    ...:     def foo(self):
    ...:         print(f"Base foo, {self.value}")
    ...:
    ...: class Derived(Base):
    ...:     value = "derived"
    ...:
    ...:     def foo(self):
    ...:         print(f"Derived foo, {self.value}")
    ...:
    ...:
    ...:     def bar(self):
    ...:         print(f"Derived bar {self.value}")
    ...:         print(super().value)
    ...:         print(super().__getattribute__("value"))
    ...:         super().foo()
    ...:         super().__getattribute__('foo')()
    ...:
    ...: d = Derived()

In [39]: Derived.mro()
Out[39]: [__main__.Derived, __main__.Base, object]
我想让你困惑的是:

super().__getattribute__("value")
在这种情况下,
super()
跳过
\uuuuuu main\uuuuuu.Derived
,在
\uuuuuuuu main\uuuuuuuuuuu.Base
中查找,没有找到任何内容,最后在
对象中查找
\uuuuuuuuu getattribute\uuuuuuu
。然后,它不会神奇地使其他所有属性访问跳过
派生
。实际上,
object.\uuuu getattribute\uuuu
无论如何都会发生,注意:

因此,当您将
“foo”
传递给
对象时,这一点也没有什么不同

In [41]: object.__getattribute__(d, 'foo')
Out[41]: <bound method Derived.foo of <__main__.Derived object at 0x7f927ba46460>>
super()。因此:

  • super().foo
    super
    代理上查找
    foo
  • super()
值得注意的是,任何一个的结果都不知道它是通过
super
查找的:对结果的任何进一步操作都将正常进行。当查找的对象是数据描述符(如方法或属性)时,它绑定到初始的
self
,而不是
super

最后,在通常情况下,查找
super()。\uuuuu getattribute\uuuuu
只会直接或通过包装器找到标准的
对象。\uuuu getattribute\uuuuu
并将其绑定到
self
。因此,调用
super()。\uuuu getattribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu(“foo”)
相当于
对象


比较表达式
super().foo
super()。\uuuu getattribute\uuuu(“foo”)
的分解方式可能会有所帮助:

#super().foo
s=超级()
foo=s.foo
#超级()
s=超级()
g=s.。\uu getattribute__
foo=g(“foo”)

在第二种情况下,
super
代理不参与查找
.foo

它总是在基类中获取属性/方法(而是方法解析顺序中的下一个类)。你认为
super
到底在哪里做不到这一点?也许,这会揭示:
object.\uuuu getattribute\uuud(value')
最近有人发布了一个非常类似的问题:@juanpa.arrivillaga:我一直认为
super()
实际上返回了基类的对象。我花了很长时间才明白,它只是一个查找一次属性的代理。@SergeBallesta你从哪里得到这个
它只是一个查找一次属性的代理
?我想让我困惑的是为什么
super().xxx
没有调用
对象。
谢谢,我仍然对
super()有点困惑。
当你说
没有找到任何东西,然后最后,在object
中找到了
中的,
Base
中没有
属性,为什么找不到它?我在Functiont
bar
中尝试了另一种方法,当我使用
super()时,bar
会因为
AttributeError而失败:“super”对象没有属性“bar”
,为什么它不会返回到
对象。uuu_ugetAttribute_uud,'bar')
?@kuixiong
value
是不相关的,
super()
正在解析
\uuuu getattribute\uuu
,而不是
super()。\uuuuGetAttribute\uuuuuuuuuuuuuuuuuuuu是对象。\uuuuuuuuuuuuuuuu属性
。谢谢,我想现在我得到了一个表面的原因,
super()。\uuuuuuuuuuuGetAttribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。但是你知道为什么
super().value
不像
d.value
那样调用
\uuu getattribute\uuuu
吗?@kuixiong它确实调用
super
\uuuu getattribute\uuuuu
因为
super().value
正在调用
super
对象上的
.value
。为什么?我以为
\uuuuuuGetAttribute\uuuuuu
会在您每次访问一个实例的属性时被调用,谢谢,您的回答真的让我明白了,我从来没有意识到
s.\uuuuuuGetAttribute\uuuuuuuuuu
s.\uuuuuuuu getattribute('foo')
在这种情况下是两个步骤(只是忘记了当与此
super()
调用结合使用时,
函数
也是一个可调用对象)。
In [41]: object.__getattribute__(d, 'foo')
Out[41]: <bound method Derived.foo of <__main__.Derived object at 0x7f927ba46460>>
In [42]: Base.foo(d)
Base foo, derived