Re: [問題] 多重繼承以及super()

看板Python作者 (djshen)時間7年前 (2018/08/10 01:55), 編輯推噓1(101)
留言2則, 2人參與, 7年前最新討論串2/2 (看更多)
※ 引述《lv100 (Tsl)》之銘言: : 各位python版的前輩大家好 : 最近小弟在自學python : 到了多重繼承的這邊有點小疑問 : 程式碼如下: : class Base(object): : def __init__(self): : print ("enter Base") : print ("leave Base") : class A(Base): : def __init__(self): : print ("enter A") : super(A, self).__init__() : print ("leave A") : class B(Base): : def __init__(self): : print ("enter B") : super(B, self).__init__() : print ("leave B") : class C(A, B): : def __init__(self): : print ("enter C") : super(C, self).__init__() : print ("leave C") : c = C() : 輸出的是: : enter C : enter A : enter B : enter Base : leave Base : leave B : leave A : leave C : 我知道多重繼承中 : super()調用的順序是根據MRO列表的順序 : 所以到leave Base都可以理解 : 疑問的點在於leave B->leave A->leave C的順序 : 想請問這邊程式是怎麼運行才會是如輸出的順序 : 感謝各位的解答 翻了一下source code 相關的應該在這 https://github.com/python/cpython/blob/master/Objects/typeobject.c 當你call super(C, self)的時候 會產生一個super object 印出來長這樣 <super: <class 'C'>, <C object>> 實驗看看在每個class的__init__裡面的super(...).__init__()後面 都加上 print(super(X, self)) call C()的時候印出的是 <super: <class 'Base'>, <C object>> <super: <class 'B'>, <C object>> <super: <class 'A'>, <C object>> <super: <class 'C'>, <C object>> call B()的時候印出 <super: <class 'Base'>, <B object>> <super: <class 'B'>, <B object>> 再來看source code裡面的 super_init function 大概就知道他在做什麼 最後面的地方 Py_XSETREF(su->type, type); Py_XSETREF(su->obj, obj); Py_XSETREF(su->obj_type, obj_type); 以<super: <class 'A'>, <C object>>來講 su->type 就是 A su->obj_type 就是 C 以上講的是 super(C, self) 發生的事 接下來要從這 super(C, self) 裡面拿 __init__ 這個attribute 相關的code在 super_getattro function裡面 這邊沒什麼問題 就是拿到 A.__init__ 但是在要從 super(A, self) 裡面拿 __init__ 的時候就不太一樣了 前面看到現在的 super(A, self) 其實是 <super: <class 'A'>, <C object>> 進到 super_getattro 以後 starttype = su->obj_type; // 拿到 C mro = starttype->tp_mro; // 拿到 [C, A, B, Base, object] // 找 A 在 mro 裡的下一個 for (i = 0; i+1 < n; i++) { if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) break; } i++; 剩下的code就是從 C 的 mro 的第 i 個裡面取attribute 從上面可以看到 <super: <class 'A'>, <C object>>.__init__ 拿到的其實是 B.__init__ 然後 <super: <class 'B'>, <C object>>.__init__ 拿到的是 B 在 C 的 mro 裡面的下一個 也就是 Base.__init__ 這就說明了為什麼輸出順序是這樣 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.226.11.47 ※ 文章網址: https://www.ptt.cc/bbs/Python/M.1533837306.A.0E8.html

08/10 02:11, 7年前 , 1F
其實官方文件就有寫getattr和super的search order一樣
08/10 02:11, 1F

08/11 00:34, 7年前 , 2F
感謝解答!!
08/11 00:34, 2F
文章代碼(AID): #1RR7_w3e (Python)
討論串 (同標題文章)
文章代碼(AID): #1RR7_w3e (Python)