如何解决为什么调用 super().foo 和 super().__getattribute__("foo") 有区别
我认为 super() 会一直尝试使用基类中的方法(或属性)运行,直到我遇到使用 super().__getattribute__("foo")
获取子类的属性的用例。简化代码如下。
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
有点超出我之前的理解,只有__getattribute__
是个例外吗?我无法获得有关此 doc 的更多详细信息,希望有人能帮助我更清楚地理解这一点,谢谢!
编辑以关注 __getattribute__
问题,如下所示:
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,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
解决方法
super()
助手创建了一个代理,该代理可以修改自身的属性访问。因此:
-
super().foo
在foo
代理上查找super
。 -
super().__getattribute__
在__getattribute__
代理上查找super
。
值得注意的是,任何一个的结果都不知道它是通过 super
查找的:对结果的任何进一步操作都照常进行。当查找的事物是数据描述符(如方法或属性)时,它绑定到初始 self
,而不是 super
。
最终,在通常情况下,查找 super().__getattribute__
只会直接或通过包装器找到标准的 object.__getattribute__
并将其绑定到 self
。因此,调用 super().__getattribute__("foo")
等效于 object.__getattribute__(self,"foo")
– 查找 super
不涉及 .foo
。
比较表达式 super().foo
和 super().__getattribute__("foo")
的分解方式可能会有所帮助:
# super().foo
s = super()
foo = s.foo
# super().__getattribute__("foo")
s = super()
g = s.__getattribute__
foo = g("foo")
在第二种情况下,super
代理不参与查找 .foo
。
更具体地说,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()
跳过 __main__.Derived
,在 __main__.Base
中查找,没有找到任何东西,最后,在 __getattribute__
中找到 object
.然后它不会神奇地使所有其他属性访问跳过 Derived
。确实,object.__getattribute__
是无论如何,注意:
In [40]: object.__getattribute__(d,'value')
Out[40]: 'derived'
因此,当您将 "foo"
传递给 object.__getattribute__
时,这没有什么不同,
In [41]: object.__getattribute__(d,'foo')
Out[41]: <bound method Derived.foo of <__main__.Derived object at 0x7f927ba46460>>
现在,当您调用 super().foo
时,它跳过 __main__.Derived
,查找 __main__.Base
并找到一个 foo
,因此本质上是:
In [42]: Base.foo(d)
Base foo,derived
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。