Python 學習筆記之類「物件導向,超類,抽象」
Python 學習筆記之類「物件導向,超類,抽象」
物件魔法
在物件導向程式設計中,術語 物件 大致意味著一系列資料 (屬性) 以及一套訪問和操作這些資料的方法。
封裝
封裝講究結構複用,邏輯內斂,以固定介面對外提供服務。其遵循單一職責,規定每個型別僅有一個引發變化的原因。單一封裝的核心是解耦和內聚,這讓設計更簡單,清晰,程式碼更易測試和凍結,避免了不確定性。
繼承
繼承在遵循原有設計和不改變既有程式碼的前提下,新增新功能,或改進演算法。其對應開閉原則,對修改封閉,對擴充套件開放。
多型
多型特性遵循里氏替換原則,所有繼承子類應該能直接用於引用父類的場合。
我們習慣於將複雜型別的公用部分剝離出來,形成穩固的抽象類。其他引發變化的相似因素則被分離成多個子類,以確保單一職責得到遵守,並能相互替換。
我們習慣於將複雜型別的公用部分剝離出來,形成穩固的抽象類。其他引發變化的相似因素則被分離成多個子類,以確保單一職責得到遵守,並能相互替換。
場景: 先將整體框架抽象成基類,然後每個子類僅保留單一分支邏輯。
繼承和多型
定義一個名為 Animal 的 class,有一個 run() 方法可以直接列印:
class
Animal
(object):
def
run
(self):
print(
"Animal is running..."
)
當我們需要編寫 Dog 和 Cat 類時,就可以直接從 Animal 類繼承:
class
Dog
(Animal):
pass
class
Cat
(Animal):
pass
對於 Dog 來說,Animal 就是它的父類,對於 Animal 來說,Dog 就是它的子類。Cat 和 Dog 類似。
繼承的好處一:子類獲得了父類的全部功能,擴充套件子類自己的功能
上例中 Animial 實現了 run() 方法,因此,Dog 和 Cat 作為它的子類也擁有 run() 方法:
dog = Dog()
dog.run()
cat = Cat()
cat.run()
'''
Animal is running...
Animal is running...
'''
我們也可以擴充套件子類的方法,比如 Dog 類:
class
Dog
(Animal):
def
run
(self):
print(
"Dog is running..."
)
def
dog_eat
(self):
print(
"Eating bones..."
)
繼承的好處二:重寫父類的功能。
無論是 Dog 還是 Cat,它們 run() 的時候,顯示的都是 Animal is running...,而對於 Dog 和 Cat 本身,應該具有自己的 run() 特性,即: Dog is running.. 和 Cat is running...,因此,對 Dog 和 Cat 類改進如下:
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...
'''
當子類的 run() 覆蓋了父類的 run() 時候,執行時總是會呼叫子類的 run() 。
這樣,我們就獲得了繼承的另一個好處:多型。
判斷一個變數是否是某個型別可以用 isinstance() 判斷:
>>>
isinstance(dog,Animal)
>>>
isinstance(cat,Animal)
'''
True
True
'''
>>>
isinstance(dog,Dog)
>>>
isinstance(cat,Dog)
'''
True
False
'''
上面示例可以看到,dog 的資料型別既是 Animal,也是 Dog。因為 Dog 是從 Animal 繼承下來的,當我們建立 Dog 例項時,我們認為 dog 的資料型別是 Dog,但同時 dog 也是 animal 的資料型別,因為 Dog 本來就是 Animal 的一種。而 cat 的資料型別是 Animal 沒錯,但是 cat 不是 Dog 資料型別。
所以,在繼承關係中,如果一個例項的資料型別是某個子類,那它的資料型別也可以被看做是父類。但是,反過來就不行:
>>>
b = Animal()
>>>
isinstance(b, Dog)
'''
False
'''
Dog
可以看成 Animal,但 Animal 不可以看成Dog。
超類
要指定超類,可在 class 語句中的類名後加上超類名,並將其用圓括號括起。
Filter
是一個過濾序列的通用類。實際上,它不會過濾掉任何東西。
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的子類 def init(self): # 重寫超類Filter的方法init
def
init
(self):
#
重寫超類Filter的方法init
self.blocked = [
'SPAM'
]
if
__name__==
"__main__"
:
f = Filter()
f.init()
print(f.filter([
1
,
2
,
3
]))
'''
1, 2, 3
'''
Filter
類的用途在於可用作其他類 (如將 'SPAM' 從序列中過濾掉的 SPAMFilter 類) 的基類 (超類)。
if
__name__==
"__main__"
:
s = SPAMFilter()
s.init()
a = s.filter([
'SPAM'
,
'SPAM'
,
'SPAM'
,
'SPAM'
,
'eggs'
,
'bacon'
,
'SPAM'
])
print(a)
'''
['eggs', 'bacon']
'''
請注意 SPAMFilter 類的定義中有兩個要點。
-
以提供新定義的方式重寫了 Filter 類中方法 init 的定義。
-
直接從 Filter 類繼承了方法 filter 的定義,因此無需重新編寫其定義。
第二點說明了繼承很有用的原因:可以建立大量不同的過濾器類,它們都從 Filter 類派生而來,並且都使用已編寫好的方法 filter。
你可以用複數形式的 __ bases __ 來獲悉類的基類,而基類可能有多個。為說明如何繼承多個類,下面來建立幾個類。
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
'''
這被稱為多重繼承,是一個功能強大的工具。然而,除非萬不得已,否則應避免使用多重繼承,因為在有些情況下,它可能帶來意外的 “併發症”。
使用多重繼承時,有一點務必注意: 如果多個超類以不同的方式實現了同一個方法 (即有多個同名方法),必須在class 語句中小心排列這些超類,因為位於前面的類的方法將覆蓋位於後面的類的方法。
因此,在前面的示例中,如果 Calculator 類包含方法 talk,那麼這個方法將覆蓋 Talker 類的方法 talk (導致它不可訪問)。
如果像下面這樣反轉超類的排列順序:
class TalkingCalculator (Talker, Calculator): pass
將導致 Talker 的方法 talk 是可以訪問的。多個超類的超類相同時,查詢特定方法或屬性時訪問超類的順序稱為方法解析順序 (MRO),它使用的演算法非常複雜。
抽象基類
一般而言,抽象類是不能例項化的類,其職責是定義子類應實 現的一組抽象方法。
下面是一個簡單的示例:
from
abc
import
ABC, abstractmethod
class
Talker
(ABC):
@abstractmethod
def
talk
(self):
pass
這裡的要點是你使用 @abstractmethod 來將方法標記為抽象的 —— 在子類中必須實現的方法。
如果你使用的是較舊的 Python 版本,將無法在模組 abc 中找到 ABC 類。在這種情況下,需要匯入ABCMeta,並在類定義開頭包含程式碼行 __ metaclass __ = ABCMeta (緊跟在 class 語句後面並縮排)。如果你使用的是 3.4 之前的 Python 3 版本,也可使用 Talker(metaclass=ABCMeta) 代替 Talker(ABC)。
抽象類(即包含抽象方法的類)最重要的特徵是不能例項化。
>>
> Talker()
Traceback (most recent call last):
File
"<stdin>"
, line
1
,
in
<
module
>
TypeError:
Can
't instantiate abstract class Talker with abstract methods talk
假設像下面這樣從它派生出一個子類:
class
Knigget
(Talker):
pass
由於沒有重寫方法 talk,因此這個類也是抽象的,不能例項化。如果你試圖這樣做,將出現類似於前面的錯誤訊息。然而,你可重新編寫這個類,使其實現要求的方法。
class
Knigget
(Talker):
def
talk
(self):
print(
"Ni!"
)
現在例項化它沒有任何問題。這是抽象基類的主要用途,而且只有在這種情形下使用 isinstance 才是妥當的:如果先檢查給定的例項確實是 Talker 物件,就能相信這個例項在需要的情況下有方法 talk。
>
>> k = Knigget()
>
>> isinstance(k, Talker) True
>
>> k.talk()
Ni!
總結
將相關的東西放在一起。 如果一個函式操作一個全域性變數,最好將它們作為一個類的屬性和方法。
不要讓物件之間過於親密。 方法應只關心其所屬例項的屬性,對於其他例項的狀態,讓它們自己去管理就好了。
慎用繼承,尤其是多重繼承。 繼承有時很有用,但在有些情況下可能帶來不必要的複雜性。要正確地使用多重繼承很難,要排除其中的 bug 更難。
保持簡單,讓方法短小緊湊。 一般而言,應確保大多數方法都能在 30 秒內讀完並理解。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29829936/viewspace-2158498/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 物件導向-抽象類物件抽象
- JAVA物件導向--抽象類Java物件抽象
- Python學習筆記|Python之物件導向Python筆記物件
- Python 3 學習筆記之——物件導向Python筆記物件
- PHP 手冊 (類與物件) 學習筆記十:抽象類PHP物件筆記抽象
- Java學習筆記之介面和抽象類Java筆記抽象
- 物件導向 -- 三大特性之繼承 補充 抽象類 介面類物件繼承抽象
- 【python 物件導向】 python物件學習筆記《1》Python物件筆記
- JAVA學習線路:day01物件導向(繼承、抽象類)Java物件繼承抽象
- 抽象類特點 學習筆記抽象筆記
- Java學習筆記之類和物件Java筆記物件
- Python學習之路——類-物件導向程式設計Python物件程式設計
- Scala 學習筆記(2)之類和物件筆記物件
- python-程式導向、物件導向、類Python物件
- 物件導向之內部類物件
- python物件導向思想(類與物件)Python物件
- Lua學習筆記--物件導向(三)筆記物件
- 【python】物件導向之類成員(屬性)Python物件
- C#學習筆記(一)--- 物件導向的思想和類的定義、物件的建立C#筆記物件
- JavaSE第三章 物件導向 抽象類 abstractJava物件抽象
- 物件導向基礎(2)--抽象類 介面 集合 泛型物件抽象泛型
- [.net 物件導向程式設計基礎] (15) 抽象類物件程式設計抽象
- Python 物件導向筆記Python物件筆記
- 抽象類的成員特點 學習筆記抽象筆記
- Flutter學習筆記(8)--Dart物件導向Flutter筆記Dart物件
- js高階 物件導向 學習筆記JS物件筆記
- Ext學習筆記2-物件導向筆記物件
- Python進階之物件導向(類的特殊方法)Python物件
- Perl物件導向--類物件
- Go 筆記之物件導向Go筆記物件
- 章10——物件導向程式設計(高階部分)——抽象類物件程式設計抽象
- Java物件導向——類與物件Java物件
- Web 開發學習筆記(5) — 抽象出 Page 類Web筆記抽象
- python3筆記---抽象類例子Python筆記抽象
- PHP 手冊 (類與物件) 學習筆記三:類常量PHP物件筆記
- Python - 物件導向程式設計 - 什麼是 Python 類、類物件、例項物件Python物件程式設計
- Python3:物件導向程式設計學習筆記(2)Python物件程式設計筆記
- Python 3 學習筆記之類與例項Python筆記