Python OOP知識積累
目錄
目錄
前言
對象
類
面向對象
Python 面向對象編程三個基本特征
封裝
繼承
繼承的作用
泛化與特化
實現繼承的方式
多重繼承
多態
方法多態
最后
前言
Python是一個功能非常強大的編程語言、玩法很多。但是在我們享受Python帶來的編程樂趣之前,我們必須要掌握OOP編程技能,這樣才能夠更好的應用Python高級功能。OOP我曾經在《Python_基礎知識儲備》中提到過,這次我們再全面而詳細的回爐一次。
對象
在計算機領域中,對象是人們要進行研究的任何事物,它表示具體的事物,此外也表示抽象的規則、計劃或事件。對象是數據和操作數據的方法的結合。
對象的狀態(數據):一個對象用數據值來描述它的狀態,也稱為對象屬性。
對象的行為(操作):對象的行為用于改變對象的狀態,也稱為對象方法。
對象唯一性(句柄):即對象名稱,每個對象都有自身唯一的標識,通過這種標識,可找到相應的對象。在對象的整個生命期中,它的標識都不改變。
對象之間的通信:對象之間進行通信的結構叫做消息,當一個消息發送給某個對象時,消息應該包含下面幾種信息:
1. 接受消息的對象名(目的對象名)。
2. 接收對象去執行某種操作的信息(調用方法名)。
3. 發送給該對象的參數,參數可以是該對象私有的變量名,或者是所有對象都知道的全局變量名。
4. 發送給該對象的消息名(源消息名)。
類
具有相同特性(數據元素)和行為(方法)的對象的抽象就是類,類本質是一種數據結構。對象的抽象是類,類的具體個性化就是對象。
類的屬性:它是對象的狀態的抽象,用數據結構來描述類的屬性,也稱為成員屬性。
類的方法:它是對象的行為的抽象,用操作名和實現該操作的方法來描述,也稱為成員方法。
類的結構:在客觀世界中有若干類,這些類之間有一定的結構關系。通常有下面兩種主要的結構關系:
1. 一般/具體結構稱為分類結構,也可以說是is a關系。用來描述在繼承中子類與父類的關系,即一個派生子類的實例化對象是其父類的一個”例子”。所以有”is a”的關系。
2. 整體/部分結構稱為組裝結構,它們之間的關系是has a關系。”組合”是實現繼承的方式之一,在”組合”繼承中,一個子類可以有多個父類,即一個子類”has a”一個父類。
面向對象
面向對象(Object Oriented,OO),面向對象是一種對現實世界理解和抽象的方法,是計算機編程技術發展到一定階段后的產物。在Python中一切皆對象,通過面向對象的思維,將現實世界的事物都抽象成為對象,將現實世界中的關系抽象成類、繼承,幫助人們實現對現實世界的抽象與數字建模。通過面向對象的方法,更利于用人理解的方式對復雜系統進行分析、設計與編程。而且,面向對象能有效提高編程的效率,通過封裝技術,消息機制可以像搭積木的一樣快速開發出一個全新的系統。其中對象是類的集合,面向對象思維將對象作為程序的基本單元,將程序和數據封裝其中,以提高軟件的重用性、靈活性和可擴展性。
面向對象編程踏上了進化的階梯,增強了結構化編程,實現了數據與動作的融合:數據層和邏輯層現在由一個可用以創建這些對象的簡單抽象層來描述。
OO后來又擴展為OOA/OOD/OOP:
OOA(Object Oriented Analysis)面向對象分析:即根據抽象關鍵的問題域來分解系統。
OOD(Object Oriented Design)面向對象設計:是一種提供符號設計系統的面向對象的實現過程,它用非常接近實際領域術語的方法把系統構造成“現實世界”的對象。
OOP(Object Oriented Programming)面向對象編程:是一種程序設計范型,同時也是一種程序開發的方法,實現OOP的程序希望能夠在程序中包含各種獨立而又互相調用的對象,每一個對象又都應該能夠接受數據、處理數據并將數據傳達給其它對象,因此每個對象都可以被看作一個小型的”機器”,而整個程序系統就是由這些小機器相互協助、組合構建起來的。
Python 面向對象編程三個基本特征
封裝
封裝描述了對數據/信息進行隱藏的觀念,它對數據屬性提供接口(接口函數)和訪問方法。在類的設計時,為數據提供了相應的接口,以免客戶程序通過不規范的操作來存取封裝的數據屬性。
封裝的目的:就是把客觀事物抽象并封裝成類,封裝好的每一個類都是獨立的,而由類實例化創建的對象亦是如此。對象之間只能通過 消息 這種通信結構來實現通訊。這樣做能夠實現:類自己的數據和方法只讓可信的類或者對象操作,對不可信操作的進行信息隱藏。為類和對象中的方法、屬性提供了安全的保障。
封裝的作用:一個類就是一個封裝了數據以及操作這些數據的方法的邏輯實體。在一個對象內部,某些方法或屬性可以是私有的(實例化對象將類中定義的私有屬性和方法個性化),它們不能被外界訪問。通過封裝,為對象內部的數據提供了不同級別的保護,以防止程序中無關的部分意外的改變或錯誤的使用了對象的私有部分。即隱藏類的功能實現的細節,使代碼模塊化(松耦合、高內聚)。
封裝的意義:一般的,我們會認為程序=數據結構+算法,在OOP中,因為封裝的存在,我們會將這條等式轉化為程序=對象+消息。
#fileName =encapsulation.py #coding = utf8 _metaclass_ = type #確定使用新式類;新式類必須繼承Object基類,并且新式類提供了對類的方法和靜態方法的支持。 class TestEncapsulation(object): def __init__(self): #構造函數,在程序啟動時自動調用,一般作為實例化對象的初始化 self.statement = "Start" print(self.statement) def accessibleMethod(self): #綁定方法,能在類外部被訪問;綁定方法一定要有self形參,self表示類本身,用于傳遞當前類中的成員屬性和方法,但是self不接收實參。 print("You can access this method!",end='') print(self.statement) print("the secert message is:") self.__inaccessible() def __inaccessible(self): #私有方法,不能在類外部被訪問;方法名以'__'開頭 print("You cannot access!") @staticmethod def staticMethod(): #self.accessibleMethod() #靜態方法無法直接調用綁定方法。因為靜態方法沒有self形參 print("This is a static method") def setStatement(self,statement): #訪問器 self.Statement = statement def getStatement(self): #訪問器 return self.Statement statement = property(fget = getStatement,fset = setStatement) #自動調用訪問器設定屬性值 #property(fget=None, fset=None, fdel=None, doc=None) --> fget is a function to be used for getting an attribute value, and likewise fset is a function for setting, and fdel a function for del'ing, anattribute. Typical use is to define a managed attribute x: name = "Jmilk" if __name__ == "__main__": test = TestEncapsulation() #類的實例化調用 test.accessibleMethod() test.staticMethod() #test.__inaccessible() #類的私有方法的命名空間只在類的范圍中,在類外不能調用 print(TestEncapsulation.name) print(test.getStatement()) test.setStatement("Just test") print(test.getStatement())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
OUTPUT:
In [56]: %run encapsulation.py Start You can access this method!Start the secert message is: You cannot access! This is a static method Jmilk Start Just test
1
2
3
4
5
6
7
8
9
上面的例子是一個簡單的封裝,在Class中定義了各種不同類型的方法和屬性,他們都有著屬于自己的命名空間和訪問限制。
公有屬性:類內外都可以被訪問
私有屬性:只能被類內函數調用,以’__’開頭。
內置屬性:系統在定義類時默認添加,命名格式為’__X__’
繼承
繼承令不同類之間擁有了一定的結構與關系。
類之間的關系:
1. 通過繼承創建的新類稱為”子類”或”派生類”
2. 被繼承的類稱為”基類”、”父類”或”超類”
繼承的作用
通過繼承得來的子類能夠保留父類中所有需要的數據和行為,同時允許修改或者其他自定義的操作,這些都不會影響到父類。換句話說,繼承的新類(子類),能夠使用被繼承類(父類)的所有功能,并且繼承后的子類能夠在無需重寫這些屬性和方法的情況下對父類的功能進行擴展。所以說,繼承就是從一般(父類)到特殊(子類)的過程。所以繼承最明顯的好處在于代碼的復用。
泛化與特化
泛化表示所有的子類與其父類及祖先類有著一樣的特點。
特化描述所有的子類的自定義,也就是,什么屬性讓它與其父類一同。
實現繼承的方式
要實現繼承,可以通過”繼承”(Inheritance)和”組合”(Composition)來實現。其中”繼承”又有實現繼承和可視繼承,”組合”又有接口繼承和純虛類。
實現繼承:子類的屬性和方法完全繼承于父類。
可視繼承:子類繼承父類的外觀和方法。
接口繼承:子類的屬性明和方法名繼承于父類,但是具體的屬性值和方法實現由子類重寫。
#coding = utf8 #fileName=inherit.py _metaclass_ = type #確定使用新式類 class Animal(object): def __init__(self): self.name = "Animal" print(self.name) def move(self,meters): print("%s moved %sm." % (self.name,meters)) class GeneralAnimal(Animal): #實現繼承,子類屬性、方法完全繼承于父類 pass class Cat(Animal): #對父類的方法進行重寫,屬性、方法定義繼承于父類,但是具體的屬性值和方法實現由子類決定 def __init__(self): #重寫父類的構造方法 self.name = 'Cat' def move(self,meters): #重寫父類的綁定方法 print("Cat never moves than 1m") class RobotCat(Animal): def __init__(self): self.name = "RobotCat" def move(self,meters): print("RobotCat move flying.") if __name__ == '__main__': animal = Animal() animal.move(10) print("----------------") generalanimal = GeneralAnimal() #實現繼承子類實例化后的對象,與父類對象的區別只有對象句柄不一致 generalanimal.move(10) print("----------------") cat = Cat() #接口繼承子類,重寫了方法實現 cat.move(100) print("----------------") robotCat = RobotCat() robotCat.move(1000)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
OUTPUT:
In [21]: %run inherit.py Animal Animal moved 10m. ---------------- Animal Animal moved 10m. ---------------- Cat never moves than 1m ---------------- RobotCat move flying.
1
2
3
4
5
6
7
8
9
10
多重繼承
Python支持多重繼承,即’組合’繼承。在Java或C#中使用接口的概念來實現多重繼承的效果。而在Python中在定義類的時候,可以直接繼承多個父類來實現多重繼承。
#coding=utf8 #fileName = multipleInherit.py _metaclass_=type # 確定使用新式類 class Animal: def eat(self,food): print("eat %s" %food) def move(self,kilometers): pass class Robot: def fly(self,kilometers): print("flyed %skm." %kilometers) class RobotCat(Animal,Robot): #繼承多個父類 def __init__(self): self.Name="Doraemon" if __name__ == '__main__': robot=RobotCat() #一只可以吃東西的會飛行的叫哆啦A夢的機器貓 print(robot.Name) robot.eat("cookies") #從動物繼承而來的eat robot.fly(10000000) #從機器繼承而來的fly
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
上面例子中由類RobotCat()實例化的對象robot,具有由兩個父類組合而成的屬性和方法。
注意:在實現多重繼承時,如果繼承的多個父類中均有名稱相同的方法時,要注意繼承的順序。
_metaclass_=type # 確定使用新式類 class Animal: def eat(self,food): print("eat %s" %food) def move(self,kilometers): #動物的move方法 pass class Robot: def move(self,kilometers): #機器的move方法 print("flyed %skm." %kilometers) class RobotCat(Animal,Robot): #繼承class Animal的eat()和move()方法,將class Robot的move()方法屏蔽了。所以這個順序是我們所不希望的 #class RobotCat(Robot,Animal): #這個是正確的順序,即能繼承Animal的eat(),又能繼承Robot的move() def __init__(self): self.Name="Doraemon" robot=RobotCat() print(robot.Name) print("---------------") robot.eat("cookies") print("---------------") robot.move(10000000)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
OUTPUT:
In [31]: %run multipleInherit.py Doraemon --------------- eat cookies ---------------
1
2
3
4
5
多態
多態的概念指出了不同的對象如何通過他們共同的屬性和動作來操作以及訪問,而不需考慮他們具體的類,多態表明了動態綁定(運行時)的存在,允許重載及運行時類型確定和驗證。
多態就是指不同的類實例(對象)都擁有相同方法和屬性,而這些相同的方法和屬性在不同情形有著不同的表現形式。多態機制使不同的對象可以共享相同的外部接口(屬性名、方法名)。這意味著,雖然針對不同對象的具體操作(方法實現)不同,但通過一個公共的類,它們可以通過相同的方式(屬性名、變量名)予以調用。即在不同的對象中可以定義同名屬性或方法,但是屬性值或方法實現卻是各不相同的。
多態的作用:實現了接口重用,保證了在類發生繼承或派生時,我們仍然能夠正確的調用這些相關類的實例化對象的屬性和方法。
方法多態
#coding=utf8 #fileName = polymorphic.py from random import choice _metaclass_=type class calculator: def count(self,args): #定義calculator類的成員函數count() return 1 calc=calculator() obj=choice(['hello,world',[1,2,3],calc]) #這里隨機返回一個不確定類型的對象,并且每個對象中都重寫了count()方法 print(type(obj)) print(obj.count('a'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OUTPUT:
In [42]: %run polymorphic.py
1
2
3
4
5
6
7
8
9
10
11
從結果中可以看出,我們在調用了不同的對象的相同的方法時,這個方法有著不一樣的表現形式。
再舉一個栗子:Duck Typing
_metaclass_=type #在Duck類和Person類中都定義了相同的方法接口,和不同的方法實現 class Duck: def quack(self): print("Quaaaaaack!") def feathers(self): print("The duck has white and gray feathers.") class Person: def quack(self): print("The person imitates a duck.") def feathers(self): print("The person takes a feather from the ground and shows it.") def in_the_forest(obj): #這個方法實現了訪問參數對象的方法 obj.quack() obj.feathers() def game(): donald = Duck() john = Person() print("------------") in_the_forest(donald) print("------------") in_the_forest(john) game()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
OUTPUT:
In [50]: %run duck.py ------------ Quaaaaaack! The duck has white and gray feathers. ------------ The person imitates a duck. The person takes a feather from the ground and shows it.
1
2
3
4
5
6
7
最后
在了解了OOP的基本知識后,就繼續通過代碼實現來加深理解吧。 : -)
Python 面向對象編程
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。