繼承、抽象類、多繼承


# 繼承的引子
# 假設我們現在有一個游戲,游戲中有這些具體的事物(對象 ): 梅西、奧巴馬、史努比、史派克、小豬配齊、豬八戒。
# 采取面向對象設計的方法,是要對游戲中的具體對象,進行分門別類的抽象,抽取中相似對象的共同特征和行為來,作為一種規范,
# 一種模板來,梅西和奧巴馬,它們的相似,具有人的特征,因此,我們把它們歸為一類,即人類,就抽象出人類這一概念來了。
# 史努力和史派克 具有共同的特征和行為,我們把它們歸為一類,並取名為狗類,完成具體到綜合的第一次抽象,而小豬配齊和希豬八戒,
# 它們兩個具體的事物,又具有共性的東西,因此將它們歸為一類,並取名為豬類。
# 以上,通過對抽取相似具體事物的共同特征,歸為一類,完成了事物的第一層抽象。
# 梅西、奧巴馬、史努比、史派克、小豬配齊、豬八戒 ===》 人類 、狗類 、 豬類 # 基本的分類
# 人類 、狗類 、 豬類 ===》 經過再一次抽象,抽象出 動物類。
# 因此面向對象的過程,就是由具體 到 抽象 的過程。從宏觀上,概念上 統領相似事物。抽象的層次,越高,能夠描述和規范的事物就越多。
# # 貓類:
# 屬性: 名字,品種,食物
# 方法: 叫,抓老鼠,吃,喝
# 狗類:
# 屬性: 名字,品種,食物
# 方法:叫,看家,吃,喝
# 人類:
# 屬性:名字,品種,食物
# 方法:說話,工作,吃,喝
# 雖然,我們從具體的事物,抽象出三個類別,但是我們發現,這三類之間,還有共同的代碼,沒有提高代碼的重用性。
# 於是乎,我們可以將三個類別的共同代碼,再抽取出來,建立一個類別,比如說叫動物類,它讓貓類、狗類、人類隸屬於這個類,
# 也就具有這個類的屬性。
# 那么用puthon代碼如何實現呢?

# 定義 一個 Animal() 的父類
class Animal: # 父類,超類,基類
def __init__(self,name,kind,food,language):
self.name = name
self.kind = kind
self.food = food
self.language = language

def yell(self):
print("%s叫" % self.language)

def eat(self):
print("吃%s" % self.food)

def drink(self):
print("喝水")

# 定義 類的 時候 ,繼承某個類,它將繼承父類的所有屬性 和 方法,繼承的寫法,就是將類 要繼承的父類,放在類名后面的小括號里。

class Cat(Animal): # 派生類
def catch_mouse(self):
print("抓老鼠")

class Dog(Animal): # 派生類

def __init__(self,name,kind,food,language,eye_color): # 子類重寫父類的方法,並通過super()方法,調用父類的同名方法
self.eye_color = eye_color # 派生屬性
super().__init__(name,kind,food,language) # self ,不用傳,會自動傳
def swim(self): # 派生方法
print("游泳")

def look_afte_home(self):
print("看家")

class Human(Animal): # 派生類
def __init__(self): # 這里子類對父類的方法,進行了重寫,即覆蓋了父類,此時父類的同名方法,對子類就不可見了。
self.walk_way = "直立行走"
def work(self):
print("工作")


# 在繼承關系中,被繼承的類,我們稱之為超類/基類/父類, : 比如上面的 Animal類
# 繼承的類,叫做子類/派生類: 比如上面的 Cat, Dog, Person


# 繼承與重用:是同一個事物的兩方面,類的繼承就是了為提高代碼的重用性,提高代碼的重用性,除了函數,類就是別外一種的實現方式。
# 比如說:寫了兩個類或多個類,它們有共同的代碼或邏輯,這時候就可以為它們創建一個父類,把共同的代碼或邏輯放到父類里,這時通過繼承
# 就實現了代碼的重用性。
# 繼承與重用,父類中的所有方法和屬性都被子類中使用了。
阿貓 = Cat("阿貓","花貓","魚","喵喵")
阿貓.yell()
阿貓.eat()
阿貓.drink()
print(阿貓.name)

yellDog = Dog("黃狗","土狗","骨頭","汪汪","藍色")
yellDog.eat()
yellDog.drink()
yellDog.yell()
print(yellDog.name)

xiaomin = Human() # 因為子類對父類的 __init__方法,進行了重寫,除了self以外,沒有參數,不需要手動傳參。
print(xiaomin.walk_way)
yellDog.swim()

# 總結:當子類當中有要被調用的方法 和 屬性的時候,子類的對象會直接選擇子類中的方法、變量,父類中的同名方法不會被自動執行。
# 如果我們既想要執行子類中方法,也想要執行父類中的同名方法,那么需要在子類的方法中調用父類的方法:有兩種方式:
# 父類名.方法名(...)
# super().方法名(...)

# 面試題:

class Foo:
def __init__(self): # 初始化對象實例的函數,此函數僅在調用 類名() 時執行一次
self.func() # 對象調用
def func(self):
print('in Foo')

class Son(Foo):
# def func(self):
# print("in Son")
pass

s1 = Son() # 創建了一個Son類的對象實例,並賦值給對象引用 s1。過程是,在內存中開辟一個對象空間,根據對象所屬的直接類的類
#對象指針 找尋 __init__方法執行,子類沒有,在父類中尋找,找到將對象傳遞參數self,執行 __init__函數體,執行self.func()語句,
# 對象執行一個方法,先在對象所屬直接類中,找到,直接執行,沒有找到,再到父類找,所以此處是打印 in Son

# class Foo:
# Country = 'China'
# def func(self):
# print(self.Country)
#
# class Son(Foo):
# Country = 'English'
# def func(self): # 走這個方法
# print(self.Country)
#
# s = Son()
# s.func()

# class Foo:
# Country = 'China'
# def func(self): # 走這個方法
# print(self.Country)
#
# class Son(Foo):
# Country = 'English'
#
# s = Son()
# s.func() # English

# class Foo:
# Country = 'China'
# def func(self):
# print(self.Country)
#
# class Son(Foo):pass
#
# s = Son()
# s.func() # 'China'
# 結論:始終注意,那個對象調用 ,self就是哪個對象

# 抽象類
# 工作中 公司使用抽象類 ,來規范 開發的規則。
# 源碼 別人使用抽象類

from abc import ABCMeta,abstractmethod # 從 abc 這個外部模塊中,導入 ABCMeta 類 和 abstracmethod這個用於裝飾函數的裝飾器

class Payment(metaclass=ABCMeta): # 給類的元類,傳遞一個關鍵字參數
@abstractmethod
def pay(self):pass # 抽象方法,僅有定義,沒有方法的實現

@abstractmethod
def shouqian(self):pass # 假如,把這兩行的注釋打開,如果子類不實現這個方法,程序會報錯
# a = Alipay()
# TypeError: Can't instantiate abstract class Alipay with abstract methods shouqian
def abstract(self):
print("我繼承抽象類")

class Alipay(Payment):
def pay(self,money):
print("使用支付寶支會了%s元" % money)
def shouqian(self,money):
print("使用收款方式收到%s元" % money)
class Wechatpay(Payment):
def pay(self,money):
print("使用微信支付了%s元" % money)
def shouqian(self,money):
print("使用收款方式收到%s元" % money)
class Applepay(Payment):
def pay(self,money):
print("使用applepay支付了%s元" % money)
def shouqian(self,money):
print("使用收款方式收到%s元" % money)

# def pay(obj,money):
# obj.pay(money)

a = Alipay()
a.pay(100)
a.shouqian(2000)

a.abstract() # 抽象類,也可以有普通方法,子類繼承
wechat = Wechatpay()
wechat.pay(260)
wechat.shouqian(489)

apple = Applepay()
apple.pay(159)
apple.shouqian(6000)

# 以上多個子類,繼承同一個抽象類,子類必須去實現抽象類中用@abstractmethod裝飾器裝飾的方法,否則會報錯。
# 實現了不同的對象,調用相同的方法

# 在上面的基礎上,我們來定義 一個 統一的函數,也可以叫接口

def 付錢(obj,money):
obj.pay(money)
# 這樣,func()就是一個統一的支付接口
付錢(wechat,1600)
付錢(a,3500)

def 收錢(obj,money):
obj.shouqian(money)
收錢(a,10000)
收錢(apple,30000)

# p = Payment() # 抽象類 , 不能實例化 TypeError: Can't instantiate abstract class Payment with abstract methods pay, shouqian


# 總結: 抽象類 是一種 規范
# 多人開發、復雜的需求、后期的擴展
# 手段,來幫助我們完成規范。

# 抽象類 如何創建
# 抽象類是一個規范,它基本上不會實現什么具體的功能,抽象類是不能被實例化的。
# 要想寫一個抽象類的步驟:
# from abc import ABCMeta,abstractmethod
# 在創建這個類的時候,指定 metaclass = ABCMeta
# 在你希望子類實現的方法上加一個 @abstractmethond 裝飾器
# 使用抽象類:
# 繼承這個類
# 必須實現這個類中被 @abstractmehond 裝飾器裝飾的方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM