Python superの理解

3048 ワード

原文住所:https://laike9m.com/blog/li-jie-python-super,70/
 
Python superの理解
今日知乎で1つの问题に答えて、意外にも1つの賛都がなくて、不思议で、结局これは私のとてもまじめに答えた问题の1つです.それなら貼っておいたほうがいいです.一部の内容は後で補充します.
もとの問題
Pythonで直接親クラス名で親メソッドを呼び出すことができる以上、super関数はなぜ存在しますか?例えばclass Child(Parent):def_init(self):     Parent.__Init(self)この方式はsuper(Child,self)と同じである.Init()の違いはありますか?
あなたの質問に答えると、答えはいいですが、違いはありません.しかし、この問題の答えは私にはよくないと思います.superについて話すには、まず「super」という名前が私たちに与えた干渉を無視しなければならない.
スーパーといえば親を思い浮かべるな!superはMROの次のクラスを指します!スーパーといえば親を思い浮かべるな!superはMROの次のクラスを指します!スーパーといえば親を思い浮かべるな!superはMROの次のクラスを指します!
スーパーといえば、父は初心者が犯しやすい間違いであり、私が犯した間違いでもあると思います.このことを忘れてから、この文章を見に行きます:Python’s super()considered super!これはRaymond Hettingerが書いた文章であり、世界で公認されているsuperに対する説明が最も透徹している文章でもあり、superを議論すると必ずそれに言及します(もちろんPython's Super Considered Harmfulもあります).
長い議論を見たくないなら、この答えを見に行きます.superはこのことをしています.
def super(cls, inst):
    mro = inst.__class__.mro()
    return mro[mro.index(cls) + 1]

2つのパラメータclsとinstはそれぞれ2つのことをした:1.instはMROを生成するlist 2を担当する.現在のMROのindexをclsで位置決めし、mro[index+1]を返すことがsuperの本質であることを覚えておいてください.MROはクラス継承の順序を表すMethod Resolution Orderのフルネームです.あとで詳しく話します.
例を挙げる
class Root(object):
    def __init__(self):
        print("this is Root")

class B(Root):
    def __init__(self):
        print("enter B")
        # print(self)  # this will print <__main__.d object="" at="">
        super(B, self).__init__()
        print("leave B")

class C(Root):
    def __init__(self):
        print("enter C")
        super(C, self).__init__()
        print("leave C")

class D(B, C):
    pass

d = D()
print(d.__class__.__mro__)

しゅつりょく
enter B
enter C
this is Root
leave C
leave B
(, , , , )
superが親と実質的に関連していないことを知った後、enter Bの次の文がthis is Rootではなくenter Cである理由を理解するのは難しくありません(superが「親を呼び出す方法」を表すと考えると、当然次の文がthis Rootであるべきだと思います).フローは、Bの__init__関数で次のようになります.
super(B, self).__init__()

まず,self.__class__.__mro__を取得し,ここでselfはBではなくDのinstanceであることに注意した.
(, , , , )

次に、MRO内のindexをBにより位置決めし、次を見つける.明らかにBの次はCです.そこで、Cの__init__を呼び出し、enter Cを打ち出します.
ちなみに、なぜBの__init__が呼び出されるのかというと、Dは__init__を定義していないので、MROで次のクラスを探して、__init__を定義しているかどうか、つまりBの__init__を呼び出すのかを確認します.
実はこのすべての論理はまだはっきりしていて、肝心なのはsuperがいったい何をしたのかを理解することです.
では、MROのクラスの順番はいったいどのように並んでいるのでしょうか.Python’s super() considered super!MROでは、ベースクラスは派生クラスの後ろに永遠に現れ、複数のベースクラスがあれば、ベースクラスの相対的な順序は変わらない.MROの公式文書については、The Python 2.3 Method Resolution Orderを参照してください.MROの順序に関する理論的な解釈があります.
最後の最後に、皆さんに注意してください.何のsuperだ、MROだ、new-style classを狙っているんだ.new-style classでなければ、親クラスのクラス名を正直に使って関数を呼び出しましょう.