深入理解Python面向物件的三大特性
在面向物件程式設計中,物件可以看做是資料(特性)以及由一系列可以存取、操作這些資料的方法所組成的集合。編寫程式碼時,我們可以將所有功能都寫在一個檔案裡,這樣也是可行的,但是這樣不利於程式碼的維護,你總不希望維護程式碼前,還需要從頭至尾的通讀一遍吧,就好像一間雜亂無章的房子,你想找一件想要的東西,但是需要地毯式的搜尋一遍,甚至多遍才能找到。很明顯,這樣做的話,很浪費我們的時間。
多型:顧名思義就是多種形態,即便不知道變數所引用的物件型別是什麼,依舊可以對它操作,而它也會根據物件(或類)型別的不同而表現出不同的行為。
例如 符號'+',在對數值操作和字串操作所表現出的不同行為
數值操作
1 intsum=1+2
2 print(intsum)
輸出結果: 3
字串操作:
strSum='hello'+'Python'
print(strSum)
輸出結果:helloPython
很明顯,符號'+'對數值和字串表現出了兩種行為,一種是數值的相加,一種是字串的拼接。
唯一能毀掉多型的就是使用函式顯示的檢查型別。比如type,isinstance以及issubclass函式,在不知道物件是什麼型別,但是又想對物件做點什麼
的時候,就可以使用多型,但要避免使用毀掉多型的方式。
使用案例說明這一點。
假設,我們平臺有個支付功能,使用者將商品放入購物車後計算出總價後點擊支付按鈕即可完成支付。此時使用一個元祖即可實現。
1 ('SPAM',100)
但客戶提出一個新的要求,對商品新增一個拍賣功能,誰出價最高,商品歸誰。顯然之前簡單的計算商品價格且將總價放入元祖裡已經不能滿足當前的需求,因為元祖是不可變的。
此時就需要不斷的獲取最新價格。直到競拍價格達到客戶滿意為止。為了實現這個功能,程式碼每次詢問價格的時候,物件都需要檢查當前的價格。
1 def getPrice(object):
2 if isinstance(object,tuple):
3 return object[1]
4 else:
5 return magic_network_method(object)
但此時,調皮的程式設計師,想要換另外一種方式表示商品價格。比如字典。沒關係,我們繼續更新程式碼。
1 def getPrice(object):
2 if isinstance(object,tuple):
3 return object[1]
4 elif isinstance(object,dict):
5 return int(object['price'])
6 else:
7 return magic_network_method(object)
但是如果有人希望為儲存在其他鍵下面的價格增加新的字典型別時,我們又需要更新程式碼,很明顯,這是一件很繁瑣的工作。如果我們能讓物件自己操作,每個新的物件型別都可以檢索和計算自己的價格並返回結果,且只需要向它詢問價格即可。這時候,多型就可以幫我們解決這個問題。
多型和方法:
程式接收一個物件,完全不瞭解該物件內部的實現方式,它可能有一種或多種形態(實現方式),但是我們僅需要詢問價格即可。
1 object.getPrice()
封裝:
回顧多型的概念,多型是指讓使用者對於不知道是什麼類(物件型別)的物件進行方法呼叫。例如
1 def Add(x,y):
2 print( x+y)
3 Add(1,2)
4 Add('hello ','world')
輸出結果:
3
hello world
當我們的Add方法寫好後,呼叫者只要知道傳入幾個引數,但並不需要知道該方法的實現細節(即便是簡單的print (x+y))也不需要關心引數型別是什麼(第一個是兩個數值,第二個是兩個字串),因為他僅僅關心的是輸出的結果3或hello world.其實封裝跟多型類似,但又有所不同。封裝僅不需要關心物件是如何構建的而可以直接使用。
繼承:先看如下程式碼
1 class Person:
2 def __init__(self,name,age,address):
3 self.name=name
4 self.age=age
5 self.address=address
6 def say(self):
7 print('你好,我叫 %s我今年%s歲 我來自%s 職業不詳 '%(self.name,self.age,self.address))
8 person=Person(name='張三',age=18,address='beijing')
9 person.say()
10
11 class Student(Person):
12 def __init__(self,name,age,address,job):
13 self.job=job
14 Person.__init__(self,name=name,age=age,address=address)
15 def say(self):
16 print('你好,我叫 %s我今年%s歲 我來自%s 我是%s,我正在學習Python教程'%(self.name,self.age,self.address,self.job))
17 men=Student(name='李四',age='18',address='河北',job='學生')
18 men.say()
19 class Teacher(Person):
20 def __init__(self,name,age,address,job):
21 self.job=job
22 Person.__init__(self,name=name,age=age,address=address)
23 def say(self):
24 print('你好,我叫 %s我今年%s歲 我來自%s 我是%s,我正在教授Python教程'%(self.name,self.age,self.address,self.job))
25 teacher=Teacher(name='王五',age='28',address='河北',job='教師')
26 teacher.say()
顯示結果:
1 你好,我叫 張三我今年18歲 我來自beijing 職業不詳
2 你好,我叫 李四我今年18歲 我來自河北 我是學生,我正在學習Python教程
3 你好,我叫 王五我今年28歲 我來自河北 我是教師,我正在教授Python教程
從程式碼中可以看出,我們先寫了一個Person類,又寫了學生類和教師類且在括號中使用了之前定義的Person類。我們在學生類和教師類的例項化時(__init__)通過Person.__init__(name=name,age=age,address=address)即可在例項化學生類或教師類時同時例項化Person類中的屬性,通過程式碼可以看出,我們只在Person中對name,age,address寫了屬性賦值程式碼,但在學生類和教師類例項化時依舊可以使用。這就是Person的繼承關係。當一段程式碼或者函式被多處呼叫時,可以將該段程式碼或者函式抽象為一個物件,其他物件繼承該物件後就可以像引用自己內部屬性一樣對父類的程式碼進行操作。
Linux公社的RSS地址 :ofollow,noindex" target="_blank">https://www.linuxidc.com/rssFeed.aspx
本文永久更新連結地址:https://www.linuxidc.com/Linux/2018-10/154606.htm