在面向對象程式設計中,對象可以看做是數據(特性)以及由一系列可以存取、操作這些數據的方法所組成的集合。編寫代碼時,我們可以將所有功能都寫在一個文件里,這樣也是可行的,但是這樣不利於代碼的維護,你總不希望維護代碼前,還需要從頭至尾的通讀一遍吧,就好像一間雜亂無章的房子,你想找一件想要的東西,但是需要地 ...
在面向對象程式設計中,對象可以看做是數據(特性)以及由一系列可以存取、操作這些數據的方法所組成的集合。編寫代碼時,我們可以將所有功能都寫在一個文件里,這樣也是可行的,但是這樣不利於代碼的維護,你總不希望維護代碼前,還需要從頭至尾的通讀一遍吧,就好像一間雜亂無章的房子,你想找一件想要的東西,但是需要地毯式的搜索一遍,甚至多遍才能找到。很明顯,這樣做的話,很浪費我們的時間。
多態:顧名思義就是多種形態,即便不知道變數所引用的對象類型是什麼,依舊可以對它操作,而它也會根據對象(或類)類型的不同而表現出不同的行為。
例如 符號'+',在對數值操作和字元串操作所表現出的不同行為
數值操作
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的繼承關係。當一段代碼或者函數被多處調用時,可以將該段代碼或者函數抽象為一個對象,其他對象繼承該對象後就可以像引用自己內部屬性一樣對父類的代碼進行操作。