python類之繼承 展開

一、繼承概述

面向對象編程 (OOP) 語言的一個主要功能就是“繼承”。繼承是指這樣一種能力:它可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下對這些功能進行擴展。

通過繼承創建的新類稱爲“子類”或“派生類”,被繼承的類稱爲“基類”、“父類”或“超類”,繼承的過程,就是從一般到特殊的過程。在某些 OOP 語言中,一個子類可以繼承多個基類。但是一般情況下,一個子類只能有一個基類,要實現多重繼承,可以通過多級繼承來實現。

繼承概念的實現方式主要有2類:實現繼承、接口繼承。

實現繼承是指使用基類的屬性和方法而無需額外編碼的能力。
接口繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現的能力(子類重構爹類方法)。

在考慮使用繼承時,有一點需要注意,那就是兩個類之間的關係應該是“屬於”關係。例如,Employee 是一個人,Manager 也是一個人,因此這兩個類都可以繼承 Person 類。但是 Leg 類卻不能繼承 Person 類,因爲腿並不是一個人。

二、實現繼承

簡單的繼承

class Person:
    def walk(self):
        print("person is walking")

class Man(Person):
    def talk(self):
        print("man is talking")

p1 = Man()
print(Man.__dict__)
p1.walk()
p1.talk()
####結果
#{'__doc__': None, 'talk': <function man.talk at 0x10330dae8>, '__module__': '__main__'}
#person is walking
#man is talking

可以看出Man類繼承了Person類的方法,但是在Man類的屬性字典中除了自己定義的talk方法並沒有walk方法,因此只有子類中沒有找到類似的方法時纔會去父類中尋找

方法重寫

class Person:
    def walk(self):
        print("person is walking")

class Man(Person):
    def walk(self):
        print("man is walking")
    def talk(self):
        print("man is talking")

p1 = Man()
x1 = Person()
p1.walk()
x1.walk()
####結果
#{'__doc__': None, 'talk': <function man.talk at 0x10330dae8>, '__module__': '__main__'}
#man is walking
#person is walking

子類可以對父類的方法進行重寫,而不會覆蓋父類的方法

使用父類的方法

方法一

父類名.方法名
class Car:
    def __init__(self,size,type,price):
        self.size = size
        self.type = type
        self.price = price

class Battery(Car):
    def __init__(self,size,type,price,battery):
        Car.__init__(self,size,type,price)
        self.battery = battery

    def show_info(self):
        print("%s的電池電量爲%s"%(self.type,self.battery))

mycar = Battery('small','E1','100w','8000A/h')
mycar.show_info()
#E1的電池電量爲8000A/h

使用此類調用父類的方法有缺陷,如果一個父類被若干個子類繼承,父類一修改類名,則會導致代碼有多處都需要修改,因此介紹方法二

方法二

super().方法名
class Car:
    def __init__(self,size,type,price):
        self.size = size
        self.type = type
        self.price = price

class Battery(Car):
    def __init__(self,size,type,price,battery):
        super().__init__(size,type,price) 
        #使用此種調用方法,也不用傳入self參數
        self.battery = battery

    def show_info(self):
        print("%s的電池電量爲%s"%(self.type,self.battery))

mycar = Battery('small','E1','100w','8000A/h')
mycar.show_info()
#E1的電池電量爲8000A/h

三、接口繼承

聲明某個子類兼容於某個父類,定義一個接口類,子類繼承接口類,並且實現接口中定義的方法。
在實踐中,接口繼承比較常見並且實用,因爲實現繼承雖然減少了代碼複用,但是這樣子類和父類的耦合度較高。
而接口繼承規定了一個兼容接口(接口就是一種方法),使得外部調用這可以使用統一的接口調用,這種方法叫做歸一化設計。
linux中的一切皆文件,是此編程思想的最典型的例子。

import abc
class All_file(metaclass=abc.ABCMeta): # All_file爲一個接口類
    @abc.abstractmethod #此裝飾器是爲了子類必須對此接口方法進行重寫,否則無法進行實例化
    def read(self): # read爲接口方法,沒有任何實際方法
        pass

    @abc.abstractmethod
    def wirte(self): # 同樣也是接口方法
        pass

class Disk(All_file):
    def read(self):
        print("Disk is reading")

    def wirte(self):
        print("Disk is wirteing")

class Mem(All_file):
    def read(self):
        print("Mem is reading")

    def wirte(self):
        print("Mem is wirteing")

四、繼承順序

若一個類繼承了多個類,那麼如果類在自己的類中找不到方法時,往父類中尋找方法的順序是不同的。其中新式類和經典類的尋找順序也不同

新式類指的是繼承了object類的子類,而經典類在定義時沒有繼承任何類。在python3中定義的類都爲新式類

#新式類的定義
class Nc(obejct):
	pass

#經典類的定義
class Ocpass

新式類的繼承順序

例子的繼承顯示

class A:
    def test(self):
        print("這是A的方法")

class B(A):
    def test(self):
        print("這是B的方法")

class C(A):
    def test(self):
        print("這是C的方法")

class D(B):
    def test(self):
        print("這是D的方法")

class E(C):
    def test(self):
        print("這是E的方法")

class F(D,E):
    def test(self):
        print("這是F的方法")
f1 = F()
print(F.__mro__) #這是新式類包含的一個內置屬性,保存了繼承順序的元祖
#(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

從例子可見新式類的繼承順序是,F-D-B-E-C-A,頂級的父類是最後被尋找的,另一種被廣泛的說法說這叫做廣度尋找

經典類的繼承順序

經典類的繼承順序和新式類不太一樣 ,繼承順序爲F-D-B-A-E-C,這一般被叫做深度尋找。先從一個分支直接尋找至頂級父類,若還沒有得到結果,則尋找分支。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章