描述
super() 函數是用於調用父類(超類)的一個方法。
super 是用來解決多重繼承問題的。(當然,單繼承也可以用。)
多重繼承,也就是我們可以爲一個類同時指定多個父類。
直接用類名調用父類方法在使用單繼承的時候沒問題,但是如果使用多繼承,會涉及到查找順序(MRO)、重複調用(鑽石繼承)等種種問題。
MRO 就是類的方法解析順序表, 其實也就是繼承父類方法時的順序表。
鑽石繼承例如:
Base
/ \
/ \
A B
\ /
\ /
C
語法
super(type[, object-or-type])
type
:類。object-or-type
:類,一般是 self
python2和python3使用super()區別
python3.x 和 python2.x 的一個區別是:
python3 可以使用直接使用 super().xxx
代替 super(Class, self).xxx
。
class A:
def add(self, x):
y = x+1
print(y)
class B(A):
def add(self, x):
super().add(x) # python2.x:super(B, self).add(x)
b = B()
b.add(2) # 3
super()單類繼承
在單類繼承中,其意義就是不需要父類的名稱來調用父類的函數,因此當子類改爲繼承其他父類的時候,不需要對子類內部的父類調用函數做任何修改就能調用新父類的方法。
# 定義父類base1 # 定義父類base2
class base1(object): # class base2(object):
def __init__(self): # def __init__(self):
print("base1 class") # print("base2 class")
# 不使用super(),若繼承父類base2,需要修改內部的父類調用函數,都換成base2
class A(base1): # class A(base2):
def __init__(self): # def __init__(self):
base1.__init__(self) # base2.__init__(self)
# 使用super(),只需要修改類的定義,第一行
class B(base1): # class B(base2):
def __init__(self): # def __init__(self):
super(B, self).__init__() # super(B, self).__init__()
這裏要注意的是
base1.__init__(self)
vs.super(B, self).__init__()
,後者:由於super將傳入self作爲調用__init__默認的第一個變量,因此在聲明的時候不需要顯式表示self。- 此外由於super返回的是代理對象,因此父類只能調用一次,也就避免瞭如下異常的可能性。
base1 = A
base1() # 無限遞歸
super()多類繼承
在多類繼承中super()是必不可少的(多類繼承是python的一大特色)。
super()的__mro__
變量記錄了方法解析搜索順序,即一個類的所有父類的調用順序(MRO用來保證多類繼承的時候各父類被逐一調用並只被調用一次)。
# -*- coding: UTF-8 -*-
# 定義父類base1
class base1(object):
def __init__(self):
pass
# 定義子類B繼承父類base1
class B(base1):
def __init__(self):
super(B, self).__init__()
# 定義子類mixin繼承父類base1
class mixin(base1):
def __init__(self):
super(mixin, self).__init__()
class C(B, mixin): # 1. mixin類插入到了B類和base1類之間
pass
if __name__ == '__main__':
C()
print(C.__mro__) # 2. 方法解析順序(MRO): C -> B -> mixin -> base1
在上述調用中,base1類不再是C類實例中B類的父類。
如果self是C類實例,super(B, self)將指向mixin類。
執行結果:
一個簡單的代碼示例
class A:
def func(self):
print('OldBoy')
class B(A):
def func(self):
super().func()
print('LuffyCity')
A().func()
B().func()
A實例化的對象調用了func方法,打印輸出了 Oldboy;
B實例化的對象調用了自己的func方法,先調用了父類的方法打印輸出了 OldBoy ,再打印輸出 LuffyCity 。
輸出結果爲:
super()使用debug過程
# -*- coding: UTF-8 -*-
class FooParent(object):
def __init__(self):
self.parent = 'I\'m the parent.'
def bar(self, message):
print("%s from Parent" % message)
class FooChild(FooParent):
def __init__(self):
# super(FooChild,self) 首先找到 FooChild 的父類(就是類 FooParent),
# 然後把類 FooChild 的對象轉換爲類 FooParent 的對象
super(FooChild, self).__init__()
def bar(self, message):
super(FooChild, self).bar(message)
print(self.parent)
if __name__ == '__main__':
fooChild = FooChild()
fooChild.bar('HelloWorld')
(1)執行fooChild = FooChild()過程
執行fooChild = FooChild()
調用class FooChild(FooParent)
類,
- 先執行
super(FooChild, self).__init__()
:首先找到 FooChild 的父類(就是class FooParent
),然後self.parent = 'I\'m the parent.'
把類 FooChild 的對象轉換爲類 FooParent 的對象。
(2)繼續執行fooChild.bar(‘HelloWorld’)過程
執行fooChild.bar('HelloWorld')
調用class FooChild的bar函數,
- 先執行
super(FooChild, self).bar(message)
:首先找到 FooChild 的父類(就是class FooParent),然後調用父類裏的bar函數,傳入參數message='HelloWorld'
,執行print("%s from Parent" % message)
,執行完這裏輸出【HelloWorld from Parent】 - 然後執行
print(self.parent)
,執行完這裏輸出【I’m the parent.】,因爲(1)中已經把類 FooChild 的對象轉換爲類 FooParent 的對象。