本文小編為大家詳細(xì)介紹“Python面向?qū)ο螅?lèi)和抽象的概念是什么”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Python面向?qū)ο螅?lèi)和抽象的概念是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。
網(wǎng)站設(shè)計(jì)制作過(guò)程拒絕使用模板建站;使用PHP+MYSQL原生開(kāi)發(fā)可交付網(wǎng)站源代碼;符合網(wǎng)站優(yōu)化排名的后臺(tái)管理系統(tǒng);成都網(wǎng)站建設(shè)、成都網(wǎng)站制作收費(fèi)合理;免費(fèi)進(jìn)行網(wǎng)站備案等企業(yè)網(wǎng)站建設(shè)一條龍服務(wù).我們是一家持續(xù)穩(wěn)定運(yùn)營(yíng)了十余年的創(chuàng)新互聯(lián)公司網(wǎng)站建設(shè)公司。
對(duì)象魔法
在面向?qū)ο缶幊讨校g(shù)語(yǔ)對(duì)象大致意味著一系列數(shù)據(jù) (屬性) 以及一套訪問(wèn)和操作這些數(shù)據(jù)的方法。
封裝
封裝講究結(jié)構(gòu)復(fù)用,邏輯內(nèi)斂,以固定接口對(duì)外提供服務(wù)。其遵循單一職責(zé),規(guī)定每個(gè)類(lèi)型僅有一個(gè)引發(fā)變化的原因。單一封裝的核心是解耦和內(nèi)聚,這讓設(shè)計(jì)更簡(jiǎn)單,清晰,代碼更易測(cè)試和凍結(jié),避免了不確定性。
繼承
繼承在遵循原有設(shè)計(jì)和不改變既有代碼的前提下,添加新功能,或改進(jìn)算法。其對(duì)應(yīng)開(kāi)閉原則,對(duì)修改封閉,對(duì)擴(kuò)展開(kāi)放。
多態(tài)
多態(tài)特性遵循里氏替換原則,所有繼承子類(lèi)應(yīng)該能直接用于引用父類(lèi)的場(chǎng)合。
我們習(xí)慣于將復(fù)雜類(lèi)型的公用部分剝離出來(lái),形成穩(wěn)固的抽象類(lèi)。其他引發(fā)變化的相似因素則被分離成多個(gè)子類(lèi),以確保單一職責(zé)得到遵守,并能相互替換。
我們習(xí)慣于將復(fù)雜類(lèi)型的公用部分剝離出來(lái),形成穩(wěn)固的抽象類(lèi)。其他引發(fā)變化的相似因素則被分離成多個(gè)子類(lèi),以確保單一職責(zé)得到遵守,并能相互替換。
場(chǎng)景:先將整體框架抽象成基類(lèi),然后每個(gè)子類(lèi)僅保留單一分支邏輯。
繼承和多態(tài)
定義一個(gè)名為 Animal 的 class,有一個(gè) run() 方法可以直接打印:
class
Animal(object):
def
run(self):
print("Animal is running...")
當(dāng)我們需要編寫(xiě) Dog 和 Cat 類(lèi)時(shí),就可以直接從 Animal 類(lèi)繼承:
class
Dog(Animal):
pass
class
Cat(Animal):
pass
對(duì)于 Dog 來(lái)說(shuō),Animal 就是它的父類(lèi),對(duì)于 Animal 來(lái)說(shuō),Dog 就是它的子類(lèi)。Cat 和 Dog 類(lèi)似。
繼承的好處一:子類(lèi)獲得了父類(lèi)的全部功能,擴(kuò)展子類(lèi)自己的功能
上例中 Animial 實(shí)現(xiàn)了 run() 方法,因此,Dog 和 Cat 作為它的子類(lèi)也擁有 run() 方法:
dog = Dog()
dog.run()
cat = Cat()
cat.run()
'''
Animal is running...
Animal is running...
'''
我們也可以擴(kuò)展子類(lèi)的方法,比如 Dog 類(lèi):
class
Dog(Animal):
def
run(self):
print("Dog is running...")
def
dog_eat(self):
print("Eating bones...")
繼承的好處二:重寫(xiě)父類(lèi)的功能。
無(wú)論是 Dog 還是 Cat,它們 run() 的時(shí)候,顯示的都是 Animal is running...,而對(duì)于 Dog 和 Cat 本身,應(yīng)該具有自己的 run() 特性,即: Dog is running.. 和 Cat is running...,因此,對(duì) Dog 和 Cat 類(lèi)改進(jìn)如下:
class
Dog(Animal):
def
run(self):
print("Dog is running...")
def
dog_eat(self):
print("Eating bone...")
class
Cat(Animal):
def
run(self):
print("Cat is running...")
def
cat_eat(self):
print("Eating fish...")
if
__name__ ==
"__main__":
dog = Dog()
dog.run()
cat = Cat()
cat.run()
'''
Dog is running...
Eating bone...
Cat is running...
Eating fish...
'''
當(dāng)子類(lèi)的 run() 覆蓋了父類(lèi)的 run() 時(shí)候,運(yùn)行時(shí)總是會(huì)調(diào)用子類(lèi)的 run() 。這樣,我們就獲得了繼承的另一個(gè)好處:多態(tài)。
判斷一個(gè)變量是否是某個(gè)類(lèi)型可以用 isinstance() 判斷:
>>>
isinstance(dog,Animal)
>>>
isinstance(cat,Animal)
'''
True
True
'''
>>>
isinstance(dog,Dog)
>>>
isinstance(cat,Dog)
'''
True
False
'''
上面示例可以看到,dog 的數(shù)據(jù)類(lèi)型既是 Animal,也是 Dog。因?yàn)?Dog 是從 Animal 繼承下來(lái)的,當(dāng)我們創(chuàng)建 Dog 實(shí)例時(shí),我們認(rèn)為 dog 的數(shù)據(jù)類(lèi)型是 Dog,但同時(shí) dog 也是 animal 的數(shù)據(jù)類(lèi)型,因?yàn)?Dog 本來(lái)就是 Animal 的一種。而 cat 的數(shù)據(jù)類(lèi)型是 Animal 沒(méi)錯(cuò),但是 cat 不是 Dog 數(shù)據(jù)類(lèi)型。
所以,在繼承關(guān)系中,如果一個(gè)實(shí)例的數(shù)據(jù)類(lèi)型是某個(gè)子類(lèi),那它的數(shù)據(jù)類(lèi)型也可以被看做是父類(lèi)。但是,反過(guò)來(lái)就不行:
>>>
b = Animal()
>>>
isinstance(b, Dog)
'''
False
'''
Dog
可以看成 Animal,但 Animal 不可以看成Dog。
超類(lèi)
要指定超類(lèi),可在 class 語(yǔ)句中的類(lèi)名后加上超類(lèi)名,并將其用圓括號(hào)括起。
Filter
是一個(gè)過(guò)濾序列的通用類(lèi)。實(shí)際上,它不會(huì)過(guò)濾掉任何東西。
class
Filter:
def
init(self):
self.blocked = []
def
filter(self, sequence):
return
[x
for
x
in
sequence
if
x
not
in
self.blocked]
class
SPAMFilter(Filter):
# SPAMFilter是Filter的子類(lèi) def init(self): # 重寫(xiě)超類(lèi)Filter的方法init
def
init(self):
#
重寫(xiě)超類(lèi)Filter的方法init
self.blocked = ['SPAM']
if
__name__=="__main__":
f = Filter()
f.init()
print(f.filter([1,
2,
3]))
'''
1, 2, 3
'''
Filter
類(lèi)的用途在于可用作其他類(lèi) (如將 'SPAM' 從序列中過(guò)濾掉的 SPAMFilter 類(lèi)) 的基類(lèi) (超類(lèi))。
if
__name__=="__main__":
s = SPAMFilter()
s.init()
a = s.filter(['SPAM',
'SPAM',
'SPAM',
'SPAM',
'eggs',
'bacon',
'SPAM'])
print(a)
'''
['eggs', 'bacon']
'''
請(qǐng)注意 SPAMFilter 類(lèi)的定義中有兩個(gè)要點(diǎn)。
以提供新定義的方式重寫(xiě)了 Filter 類(lèi)中方法 init 的定義。
直接從 Filter 類(lèi)繼承了方法 filter 的定義,因此無(wú)需重新編寫(xiě)其定義。
第二點(diǎn)說(shuō)明了繼承很有用的原因:可以創(chuàng)建大量不同的過(guò)濾器類(lèi),它們都從 Filter 類(lèi)派生而來(lái),并且都使用已編寫(xiě)好的方法 filter。
你可以用復(fù)數(shù)形式的 __ bases __ 來(lái)獲悉類(lèi)的基類(lèi),而基類(lèi)可能有多個(gè)。為說(shuō)明如何繼承多個(gè)類(lèi),下面來(lái)創(chuàng)建幾個(gè)類(lèi)。
class
Calculator:
def
calculate(self, expression):
self.value = eval(expression)
class
Talker:
def
talk(self):
print('Hi, my value is',self.value)
class
TalkingCalculator(Calculator, Talker):
pass
if
__name__=="__main__":
tc = TalkingCalculator()
tc.calculate('1 + 2 * 3')
tc.talk()
'''
Hi, my value is 7
'''
這被稱為多重繼承,是一個(gè)功能強(qiáng)大的工具。然而,除非萬(wàn)不得已,否則應(yīng)避免使用多重繼承,因?yàn)樵谟行┣闆r下,它可能帶來(lái)意外的 “并發(fā)癥”。
使用多重繼承時(shí),有一點(diǎn)務(wù)必注意:如果多個(gè)超類(lèi)以不同的方式實(shí)現(xiàn)了同一個(gè)方法 (即有多個(gè)同名方法),必須在class 語(yǔ)句中小心排列這些超類(lèi),因?yàn)槲挥谇懊娴念?lèi)的方法將覆蓋位于后面的類(lèi)的方法。
因此,在前面的示例中,如果 Calculator 類(lèi)包含方法 talk,那么這個(gè)方法將覆蓋 Talker 類(lèi)的方法 talk (導(dǎo)致它不可訪問(wèn))。
如果像下面這樣反轉(zhuǎn)超類(lèi)的排列順序:
class TalkingCalculator(Talker, Calculator): pass
將導(dǎo)致 Talker 的方法 talk 是可以訪問(wèn)的。多個(gè)超類(lèi)的超類(lèi)相同時(shí),查找特定方法或?qū)傩詴r(shí)訪問(wèn)超類(lèi)的順序稱為方法解析順序 (MRO),它使用的算法非常復(fù)雜。
抽象基類(lèi)
一般而言,抽象類(lèi)是不能實(shí)例化的類(lèi),其職責(zé)是定義子類(lèi)應(yīng)實(shí) 現(xiàn)的一組抽象方法。
下面是一個(gè)簡(jiǎn)單的示例:
from
abc
import
ABC, abstractmethod
class
Talker(ABC):
@abstractmethod
def
talk(self):
pass
這里的要點(diǎn)是你使用 @abstractmethod 來(lái)將方法標(biāo)記為抽象的 —— 在子類(lèi)中必須實(shí)現(xiàn)的方法。
如果你使用的是較舊的 Python 版本,將無(wú)法在模塊 abc 中找到 ABC 類(lèi)。在這種情況下,需要導(dǎo)入ABCMeta,并在類(lèi)定義開(kāi)頭包含代碼行 __ metaclass __ = ABCMeta (緊跟在 class 語(yǔ)句后面并縮進(jìn))。如果你使用的是 3.4 之前的 Python 3 版本,也可使用 Talker(metaclass=ABCMeta) 代替 Talker(ABC)。
抽象類(lèi)(即包含抽象方法的類(lèi))最重要的特征是不能實(shí)例化。
>>> Talker()
Traceback (most recent call last):
File
"
TypeError:
Can't instantiate abstract class Talker with abstract methods talk
假設(shè)像下面這樣從它派生出一個(gè)子類(lèi):
class
Knigget(Talker):
pass
由于沒(méi)有重寫(xiě)方法 talk,因此這個(gè)類(lèi)也是抽象的,不能實(shí)例化。如果你試圖這樣做,將出現(xiàn)類(lèi)似于前面的錯(cuò)誤消息。然而,你可重新編寫(xiě)這個(gè)類(lèi),使其實(shí)現(xiàn)要求的方法。
class
Knigget(Talker):
def
talk(self):
print("Ni!")
現(xiàn)在實(shí)例化它沒(méi)有任何問(wèn)題。這是抽象基類(lèi)的主要用途,而且只有在這種情形下使用 isinstance 才是妥當(dāng)?shù)模喝绻葯z查給定的實(shí)例確實(shí)是 Talker 對(duì)象,就能相信這個(gè)實(shí)例在需要的情況下有方法 talk。
>>> k = Knigget()
>>> isinstance(k, Talker) True
>>> k.talk()
Ni!
讀到這里,這篇“Python面向?qū)ο?,超?lèi)和抽象的概念是什么”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。