python 中 super函數

寫這篇文章來自於兩個疑問:python

1. super如何用?bash

2. 既然子類裏有繼承的父類,爲何不是父類.函數方式調用,而是super方式調用?函數

 

super如何用

super是python內置類oop

用法以下ui

super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type) -> unbound super object
super(type, type2) -> bound super object; requires issubclass(type2, type)
Typical use to call a cooperative superclass method:
class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)

 由此可知, super有三種用法, 第一參數老是調用父類的那個類, 第二參數可缺(返回非綁定父類對象),也能夠是實例對象或該類的子類. 最終返回的都是父類的實例(綁定或非綁定). 在Python3中,super函數多了一種用法是直接super(),至關於super(type,首參), 這個首參就是通常的傳入的self實例自己啦. 由於在py2裏面經常使用也是這種寫法.spa

另外, 在py2中, super只支持新類new-style class, 就是繼承自object的).code

class Base(object):
    def __init__(self):
        print("Base created")

class ChildA(Base):
    def __init__(self):
        Base.__init__(self)

class ChildB(Base):
    def __init__(self):
        super(ChildB, self).__init__()

ChildA() 
ChildB()

如上兩種方式均可正確調用父類方法,但有什麼區別?對象

目前來看是同樣的,可是若是遇到多重繼承該怎麼辦,不以下面繼承

class ChildC(ChildA, ChildB):
    def __init__(self):
        ...

假如ChildA和ChildB裏都有ChildC須要繼承的屬性,方法等,那麼類名.函數名(self)的方式就得調用兩次,這是缺點1,缺點2就是它還會重複調用it

class Base(object):
    def __init__(self):
        print("Base created")

class ChildA(Base):
    def __init__(self):
        # Base.__init__(self)
        print("ChildA created")
        super(ChildA, self).__init__()

class ChildB(Base):
    def __init__(self):
        print("ChildB created")
        super(ChildB, self).__init__()

class ChildC(ChildA, ChildB):
    def __init__(self):
        print("ChildC created")
        ChildA.__init__(self)
        ChildB.__init__(self)

c = ChildC()

# 輸出
ChildC created
ChildA created
ChildB created
Base created
ChildB created
Base created

可見ChildB Base重複調用了

若是換作super的話就可去除這2個缺點

class Base(object):
    def __init__(self):
        print("Base created")

class ChildA(Base):
    def __init__(self):
        # Base.__init__(self)
        print("ChildA created")
        super(ChildA, self).__init__()

class ChildB(Base):
    def __init__(self):
        print("ChildB created")
        super(ChildB, self).__init__()

class ChildC(ChildA, ChildB):
    def __init__(self):
        print("ChildC created")
        super(ChildC, self).__init__()

c = ChildC()
print(c.__class__.__mro__)

# 輸出
ChildC created
ChildA created
ChildB created
Base created
[<class '__main__.ChildC'>, <class '__main__.ChildA'>, <class '__main__.ChildB'>, <class '__main__.Base'>, <type 'object'>]

可見代碼整潔了,並且重複調用沒了,並且可避免直接使用父類名

super其實幹的是這件事:

def super(cls, inst):
    mro = inst.__class__.mro()
    return mro[mro.index(cls) + 1]

兩個參數 cls 和 inst 分別作了兩件事: 
1. inst 負責生成 MRO 的 list 
2. 經過 cls 定位當前 MRO 中的 index, 並返回 mro[index + 1] 
這兩件事纔是 super 的實質,必定要記住! 
MRO 全稱 Method Resolution Order,它表明了類繼承的順序。

注意super調用父類的方法時,父類裏的self都是指的當前子類的實例

class Base(object):
    n = 5
    def __init__(self, n):
        print("Base created")
        self.n += n

class ChildA(Base):
    n = 10
    def __init__(self, n):
        print("ChildA created")
        super(ChildA, self).__init__(n)
        self.n += n

c = ChildA(2)
print(c.n)
print(c.__class__.__mro__)

# 輸出
ChildA created
Base created
14
(<class '__main__.ChildA'>, <class '__main__.Base'>, <type 'object'>)

上面父類調用父類__init__(self, n)方法時,self是子類ChildA的實例c,底層c開始調用,c實例一直往上傳遞

相關文章
相關標籤/搜索