簡體   English   中英

為什么調用 super().foo 和 super().__getattribute__("foo") 有區別

[英]why is there difference between calling super().foo and super().__getattribute__("foo")

我認為 super() 總是會嘗試使用基礎 class 中的方法(或屬性)運行,直到我遇到一個用super().__getattribute__("foo")獲取子 class 屬性的用例。 簡化代碼如下所示。

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

output,

Derived bar derived
base
derived
Base foo, derived
Derived foo, derived

有點超出我之前的理解,難道只有__getattribute__是個例外嗎? 我無法獲得此文檔的更多詳細信息,希望任何人都可以幫助我更清楚地理解這一點,謝謝!


編輯以遵循__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, {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()

output 是:

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().foosuper代理上查找foo
  • super().__getattribute__super代理上查找__getattribute__

值得注意的是,任何一個的結果都不知道它是通過super查找的:對結果的任何進一步操作都會正常進行 當查找的事物是數據描述符(如方法或屬性)時,它綁定到初始self ,而不是super

最終,查找super().__getattribute__在通常情況下只會直接或通過包裝器找到標准object.__getattribute__並將其綁定到self 因此,調用super().__getattribute__("foo")等價於object.__getattribute__(self, "foo") - 沒有super參與查找.foo


比較表達式super().foosuper().__getattribute__("foo")如何被分解可能會有所幫助:

# super().foo
s = super()
foo = s.foo
# super().__getattribute__("foo")
s = super()
g = s.__getattribute__
foo = g("foo")

在第二種情況下, super代理不參與查找.foo

更具體地說, super在查找某些屬性/方法時基本上會跳過當前的 class。 在單個 inheritance 的情況下,這相當於在基礎 class 中查看。 總是在上面發生。

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中查找,沒有找到任何東西,然后最后在object中找到__getattribute__ 然后它不會神奇地使所有其他屬性訪問跳過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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM