物件導向程式設計之super內建函式的用法

任平生78發表於2017-07-07

先來看一段程式碼:

定義一個名叫People的父類,又定義了一個叫Teacher的老師類和一個叫Student的學生類
來繼承People的類,並根據這兩個子類例項化出兩個物件s1和t1

class Date:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day

    def birth_info(self):
        print("The birth is %s-%s-%s"%(self.year,self.mon,self.day))

class People:
    def __init__(self,name,age):
        self.name=name
        self.age=age


    def walk(self):
        print("%s is walking"%self.name)

class Teacher(People):
    def __init__(self,name,age,year,mon,day,course):
        People.__init__(self,name,age)
        self.course=course
        self.birth=Date(year,mon,day)

    def teach(self):
        print("%s is teaching"%self.name)

class Student(People):
    def __init__(self,name,age,year,mon,day,group):
        People.__init__(self,name,age)
        self.birth = Date(year, mon, day)
        self.group=group

    def study(self):
        print("%s is studying"%self.name)
t1=Teacher("alex",28,1989,9,2,"python")
s1=Student("jack",22,1995,2,8,"group2")

現在問題來了,假如因為需要,我要修改老師類和學生類的父類People的名字。

這樣一來,在老師類Teacher和學生類Student中繼承的類People也要修改,以及它們
呼叫的init方法的那個父類也要修改名字,太麻煩了有沒有?

這時候就可以使用super()這個內建函式來搞定了。

在python直譯器中檢視幫助資訊:

help(super)

得到如下資訊:

Help on class super in module builtins:

class super(object)
 |  super() -> same as super(__class__, <first argument>)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)

super是一個內建函式,加括號就得到一個物件,物件super()加”.”可以直接呼叫父類的init方法。

這個物件在呼叫父類的init時,實際上就是在呼叫父類的繫結方法,所以就不需要在括號里加上self了。

修改後的程式碼如下:

class Date:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day

    def birth_info(self):
        print("The birth is %s-%s-%s"%(self.year,self.mon,self.day))

class People:
    def __init__(self,name,age):
        self.name=name
        self.age=age


    def walk(self):
        print("%s is walking"%self.name)

class Teacher(People):
    def __init__(self,name,age,year,mon,day,course):
        super().__init__(name,age)
        self.course=course
        self.birth=Date(year,mon,day)

    def teach(self):
        print("%s is teaching"%self.name)

class Student(People):
    def __init__(self,name,age,year,mon,day,group):
        super().__init__(name,age)
        self.birth = Date(year, mon, day)
        self.group=group

    def study(self):
        print("%s is studying"%self.name)
t1=Teacher("alex",28,1989,9,2,"python")
s1=Student("jack",22,1995,2,8,"group2")     

這樣一來,父類的名字改變了,程式碼裡面繼承的父類的init方法的名字也不需要修改了。

python2中,也可以使用super,其呼叫方法為:super(Teacher,self)

使用super()函式時,python會在mro列表中繼續搜尋下一個類。

只要每個重定義的方法統一使用super()並只呼叫它一次,那麼控制流最終會遍歷完整個mro列表。每個方法只會呼叫一次。
使用super呼叫的所有的屬性,都是從mro列表當前的位置往後找,看mro列表的順序就可以看到子類的繼承關係

檢視上面程式碼中Teacher這個子類的mro列表可以使用這個方法:

Teacher.mro()   

使用super可以避免使用多重繼承時,子類繼承父類的順序問題。
子類繼承父類的資料屬性和函式屬性時,先執行的先生效,當後面的程式碼與前面的程式碼有衝突時,
後面的程式碼會把前面的程式碼覆蓋掉,不使用super時需要自己解決繼承的順序問題,使用super就可以很好的解決這個問題了。


相關文章