多態指的是一類事物有多種形態。python
動物有多種形態:人,狗,豬。安全
import abc class Animal(metaclass=abc.ABCMeta): #同一類事物:動物 @abc.abstractmethod def talk(self): pass class People(Animal): #動物的形態之一:人 def talk(self): print('say hello') class Dog(Animal): #動物的形態之二:狗 def talk(self): print('say wangwang') class Pig(Animal): #動物的形態之三:豬 def talk(self): print('say aoao')
文件有多種形態:文本文件,可執行文件。函數
import abc class File(metaclass=abc.ABCMeta): #同一類事物:文件 @abc.abstractmethod def click(self): pass class Text(File): #文件的形態之一:文本文件 def click(self): print('open file') class ExeFile(File): #文件的形態之二:可執行文件 def click(self): print('execute file')
什麼是多態動態綁定(在繼承的背景下使用時,有時也稱爲多態性)。spa
多態性是指在不考慮實例類型的狀況下使用實例:設計
在面向對象方法中通常是這樣表述多態性:
向不一樣的對象發送同一條消息(!!!obj.func():是調用了obj的方法func,又稱爲向obj發送了一條消息func),不一樣的對象在接收時會產生不一樣的行爲(即方法)。
也就是說,每一個對象能夠用本身的方式去響應共同的消息。所謂消息,就是調用函數,不一樣的行爲就是指不一樣的實現,即執行不一樣的函數。code好比:老師.下課鈴響了(),學生.下課鈴響了(),老師執行的是下班操做,學生執行的是放學操做,雖然兩者消息同樣,可是執行的效果不一樣。對象
peo=People() dog=Dog() pig=Pig() #peo、dog、pig都是動物,只要是動物確定有talk方法 #因而咱們能夠不用考慮它們三者的具體是什麼類型,而直接使用 peo.talk() dog.talk() pig.talk() #更進一步,咱們能夠定義一個統一的接口來使用 def func(obj): obj.talk()
隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。blog
好處:繼承
1. 將變化隔離; 接口
2. 便於使用;
3. 提升複用性;
4. 提升安全性。
封裝原則:
1. 將不須要對外提供的內容都隱藏起來;
2. 把屬性都隱藏,提供公共方法對其訪問。
在python中用雙下劃線開頭的方式將屬性隱藏起來(設置成私有的)
#其實這僅僅這是一種變形操做 #類中全部雙下劃線開頭的名稱如__x都會自動變造成:_類名__x的形式: class A: __N=0 #類的數據屬性就應該是共享的,可是語法上是能夠把類的數據屬性設置成私有的如__N,會變形爲_A__N def __init__(self): self.__X=10 #變形爲self._A__X def __foo(self): #變形爲_A__foo print('from A') def bar(self): self.__foo() #只有在類內部才能夠經過__foo的形式訪問到. #A._A__N是能夠訪問到的,即這種操做並非嚴格意義上的限制外部訪問,僅僅只是一種語法意義上的變形
這種自動變形的特色:
1.類中定義的__x只能在內部使用,如self.__x,引用的就是變形的結果。
2.這種變形其實正是針對外部的變形,在外部是沒法經過__x這個名字訪問到的。
3.在子類定義的__x不會覆蓋在父類定義的__x,由於子類中變造成了:_子類名__x,而父類中變造成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是沒法覆蓋的。
這種變形須要注意的問題是:
1.這種機制也並無真正意義上限制咱們從外部直接訪問屬性,知道了類名和屬性名就能夠拼出名字:_類名__屬性,而後就能夠訪問了,如a._A__N
2.變形的過程只在類的內部生效,在定義後的賦值操做,不會變形
3.在繼承中,父類若是不想讓子類覆蓋本身的方法,能夠將方法定義爲私有的
#正常狀況 >>> class A: ... def fa(self): ... print('from A') ... def test(self): ... self.fa() ... >>> class B(A): ... def fa(self): ... print('from B') ... >>> b=B() >>> b.test() from B #把fa定義成私有的,即__fa >>> class A: ... def __fa(self): #在定義時就變形爲_A__fa ... print('from A') ... def test(self): ... self.__fa() #只會與本身所在的類爲準,即調用_A__fa ... >>> class B(A): ... def __fa(self): ... print('from B') ... >>> b=B() >>> b.test() from A
封裝在於明確區份內外,使得類實現者能夠修改封裝內的東西而不影響外部調用者的代碼;而外部使用用者只知道一個接口(函數),只要接口(函數)名、參數不變,使用者的代碼永遠無需改變。這就提供一個良好的合做基礎——或者說,只要接口這個基礎約定不變,則代碼改變不足爲慮。
#類的設計者 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): #對外提供的接口,隱藏了內部的實現細節,此時咱們想求的是面積 return self.__width * self.__length #使用者 >>> r1=Room('臥室','egon',20,20,20) >>> r1.tell_area() #使用者調用接口tell_area #類的設計者,輕鬆的擴展了功能,而類的使用者徹底不須要改變本身的代碼 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): #對外提供的接口,隱藏內部實現,此時咱們想求的是體積,內部邏輯變了,只需求修該下列一行就能夠很簡答的實現,並且外部調用感知不到,仍然使用該方法,可是功能已經變了 return self.__width * self.__length * self.__high #對於仍然在使用tell_area接口的人來講,根本無需改動本身的代碼,就能夠用上新功能 >>> r1.tell_area()
什麼是特性property?
將一個類的函數定義成特性之後,對象再去使用的時候obj.name,根本沒法察覺本身的name是執行了一個函數而後計算出來的,這種特性的使用方式遵循了統一訪問的原則。
除此以外,看下:
ps:面向對象的封裝有三種方式:
【public】
這種其實就是不封裝,是對外公開的
【protected】
這種封裝方式對外不公開,但對朋友(friend)或者子類(形象的說法是「兒子」,但我不知道爲何你們 不說「女兒」,就像「parent」原本是「父母」的意思,但中文都是叫「父類」)公開
【private】
這種封裝對誰都不公開
python並無在語法上把它們三個內建到本身的class機制中,在C++裏通常會將全部的全部的數據都設置爲私有的,而後提供set和get方法(接口)去設置和獲取,在python中經過property方法能夠實現。
class Foo: def __init__(self,val): self.__NAME=val #將全部的數據屬性都隱藏起來 @property def name(self): return self.__NAME #obj.name訪問的是self.__NAME(這也是真實值的存放位置) @name.setter def name(self,value): if not isinstance(value,str): #在設定值以前進行類型檢查 raise TypeError('%s must be str' %value) self.__NAME=value #經過類型檢查後,將值value存放到真實的位置self.__NAME @name.deleter def name(self): raise TypeError('Can not delete') f=Foo('egon') print(f.name) # f.name=10 #拋出異常'TypeError: 10 must be str' del f.name #拋出異常'TypeError: Can not delete'
一個靜態屬性property本質就是實現了get,set,delete三種方法。
class Foo: @property def AAA(self): print('get的時候運行我啊') @AAA.setter def AAA(self,value): print('set的時候運行我啊') @AAA.deleter def AAA(self): print('delete的時候運行我啊') #只有在屬性AAA定義property後才能定義AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA
class Foo: def get_AAA(self): print('get的時候運行我啊') def set_AAA(self,value): print('set的時候運行我啊') def delete_AAA(self): print('delete的時候運行我啊') AAA=property(get_AAA,set_AAA,delete_AAA) #內置property三個參數與get,set,delete一一對應 f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA
怎麼用?
class Goods: def __init__(self): # 原價 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 實際價格 = 原價 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() obj.price # 獲取商品價格 obj.price = 200 # 修改商品原價 print(obj.price) del obj.price # 刪除商品原價
class Classmethod_Demo(): role = 'dog' @classmethod def func(cls): print(cls.role) Classmethod_Demo.func()
class Staticmethod_Demo(): role = 'dog' @staticmethod def func(): print("當普通方法用") Staticmethod_Demo.func()