pythonsuper函数_认识python中的super函数
需求分析
在類繼承中,存在這么一種情況:
class Human(object):
def Move(self):
print("我會走路...")
class Man(Human):
def Move(self):
print("我會跑步...")
man().Move()
輸出:
我會跑步...
人先會走路再會跑步的。如果你想調用Man().Move()時輸出以下要怎么做?
我會走路...
我會跑步...
這時,其實便需要調用父類Human的Move()方法了。我們知道,在子類中,會覆父類的同名方法。即子類Man里的Move()方法將父類Human中的同名方法Move()覆蓋了。要想同時使得兩個方法都奏效,可以在子類中主動調用父類中的Move()方法。其實很簡單,在類Man中加點東西就行了,如下:
class Human(object):
def Move(self):
print("我會走路...")
class Man(Human):
def Move(self):
Human.Move(self)
print("我會跑步...")
Man().Move()
output:
我會走路...
我會跑步...
代碼中的Human.Move(self)便是在子類Man中主動跟調用父類的方法。我來解釋一下這句代碼:
Human.Move(self)中Human是類,由類直接調用Move方法,這是未綁定的調用。
Human.Move(self)中的self其實是Man的一個實例Man(),一個個類的實例化是這樣的m=Man(),其中,m和Man()都是類Man的實例。
但是,這種方法有一個弊端。比如,如果父類Human吃飽沒事干給自己換個名字叫GoodHuman,那么麻煩就來了,你不僅要把Man(Human)改為Man(GoodHuman),還要把Human.Move(self)改為GoodHuman.Move(self)。
當然,這里的例子改起來是沒什么可怕。但萬一在一些項目里像Human.Move(self)這類型的方法很多的話,你要一個一個改?
有沒有什么辦法,使得在父類更改名稱時,子類只要改類似Man(Human)一處就好?
super()出場
super()的作用是:在類的繼承中,如果重定義某個方法,該方法會覆蓋父類的同名方法,但有時,我們希望能同時實現父類的功能,這時,我們就需要調用父類的方法了,可通過使用 super 來實現。
調用super()地常用格式是:
class C(B):
def meth(self, arg):
super(C, self).meth(arg)
現在,只要將代碼改為以下,就不怕父類名稱地變化了。(輸出結果和上述一樣)
class Human(object):
def Move(self):
print("我會走路...")
class Man(Human):
def Move(self):
super(Man, self).Move()
print("我會跑步...")
稍微深入
上面地例子很簡單,因為類Man繼承地父類已有一個。當繼承關系變復雜時,(比如同時繼承很多個類,繼承的類又繼承其他類等等...),便要知道super()是怎么處理繼承順序了。
看這個例子:
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")
按照前面的思路。我們意淫的輸出應該是:
enter C
enter A
enter Base
leave Base
leave A
enter B
enter Base
leave Base
leave B
leave C
但實際輸出卻是:
enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C
我在這里提一個疑問:
**enter A的下一句為什么不是enter Base而是enter B么? **
揭開super的面紗
其實,對于你定義的每一個類,Python 會用方法解析順序(Method Resolution Order, MRO)計算出一個列表,它代表了類繼承的順序,我們可以使用下面的方式獲得某個類的 MRO 列表:
>>>print(C.mro())
[, , , , ]
[Finished in 0.2s]
一個類的 MRO 列表就是合并所有父類的 MRO 列表,并遵循以下三條原則:
子類永遠在父類前面;
如果有多個父類,會根據它們在列表中的順序被檢查;
如果對下一個類存在兩個合法的選擇,選擇第一個父類.
我們查看super函數的代碼:
ef super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]
其中,cls 代表類,inst 代表實例,上面的代碼做了兩件事:
獲取 inst 的 MRO 列表;
查找 cls 在當前 MRO 列表中的 index, 并返回它的下一個類,即 mro[index + 1]。
當你使用 super(cls, inst) 時,Python 會在 inst 的 MRO 列表上搜索 cls 的下一個類。
現在我們來通過一步步追蹤來回答上面提出的答案:
做法很簡單:
1, 修改一下代碼:
class Base(object):
def __init__(self):
print("enter Base")
print("leave Base")
print(self)
class A(Base):
def __init__(self):
print("enter A")
print(self)
super(A, self).__init__()
print("leave A")
class B(Base):
def __init__(self):
print("enter B")
print(self)
super(B, self).__init__()
print("leave B")
class C(A, B):
def __init__(self):
print("enter C")
print(self)
super(C, self).__init__()
print("leave C")
c = C()
print(hex(id(c)))
看輸出:
enter C
<__main__.C object at 0x000001C614CAB7F0>
enter A
<__main__.C object at 0x000001C614CAB7F0>
enter B
<__main__.C object at 0x000001C614CAB7F0>
enter Base
leave Base
<__main__.C object at 0x000001C614CAB7F0>
leave B
leave A
leave C
0x1c614cab7f0
在這里塞了這么多代碼,就為了說明兩件事:
在A,B,C,Base這四個類中,self都是<__main__.C object at 0x000001C614CAB7F0>這個對象。
<__main__.C object at 0x000001C614CAB7F0>是類C的實例c(c的id輸出是0x1c614cab7f0,說明它們是同樣的東西)。實例c也就是整個過程的發起者。
到了這里,就可以回答問題了:
首先看類C的__init__方法:
super(C, self).__init__()
這里的 self 是當前 C 的實例,self.__class__.mro() 結果是:
[__main__.C, __main__.A, __main__.B, __main__.Base, object]
可以看到,C 的下一個類是 A,于是,跳到了 A 的 __init__,這時會打印出 enter A,并執行下面一行代碼:
super(A, self).__init__()
注意,這里的 self 也是當前 C 的實例,MRO 列表跟上面是一樣的,搜索 A 在 MRO 中的下一個類,發現是 B,于是,跳到了 B 的__init__,這時會打印出enter B,而不是enter Base。
總結
super和父類沒有實質性的關聯。通過上面分析。我們知道super函數是根據self以及該self對應的方法解析順序mro來工作的。
再強調一下,self是一個實例對象,在這里就是實例c(上面代碼有一句c=C()),整個過程的發起者。
版權:保留所有權,轉載請注明出處!
總結
以上是生活随笔為你收集整理的pythonsuper函数_认识python中的super函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python哪些模块用于数据分析_pyt
- 下一篇: python3.7怎么设置中文_解决 B