大家好,下麵我說一下我對面向對象的理解,不會講的很詳細,因為有很多人的博客都把他寫的很詳細了,所以,我儘可能簡單的通過一些代碼讓初學者可以理解面向對象及他的三個要素。 python是一門面向對象編程語言,對面相對象語言編碼的過程叫做面向對象編程。 面向對象時一種思想,與之相對對的是面向過程。我們先簡 ...
大家好,下麵我說一下我對面向對象的理解,不會講的很詳細,因為有很多人的博客都把他寫的很詳細了,所以,我儘可能簡單的通過一些代碼讓初學者可以理解面向對象及他的三個要素。
摘要:
1、首先介紹一下麵向對象 2、然後分別講一下封裝、繼承和多態 3、最後通過一段面向對象的案例來更好的理解一下麵向對象
python是一門面向對象編程語言,對面相對象語言編碼的過程叫做面向對象編程。
面向對象時一種思想,與之相對對的是面向過程。我們先簡單說一下麵向過程。
面向過程其實就是把過程當做設計核心,根據問題的發展順序,依次解決問題,儘可能的把過程中涉及到的問題完善解決。他有他的優點,當拿到一個問題時,可以方便的按執行的步驟寫代碼,但是當邏輯關係變得複雜時,有一個地方出現差錯就會導致整個程式無從下手。
既然主要是說python,那我們還是回來說說python的面向對象,面向對象的編程語言還是很多的,例如C++、Java等等。
面向對象程式設計把電腦程式的執行看做一組對象的集合,每個對象之間進行消息的傳送處理。有一個顯著的優點就是,對某個對象進行修改,整個程式不會受到影響,自定義數據類型就是面向對象中的類的概念,而我們需要把他們的介面處理好就很好辦了。說了這麼多話,有些小白已經看不下去了,那接下來我們進入主題。
- 上面說了,自定義數據類型就是面向對象中的類的概念。我們先介紹一下待會兒會用到的一些術語:
1 # 我認為還是通過個例子更容易讓人理解 2 3 # 首先我們定義一個類 4 class A(object): # 這是一個類,class是創建一個類的標誌 5 # 類變數(類屬性):類屬性是指類的屬性,屬性就是我們剛學編程的時候聽過的變數。 6 x = 7 7 y = "asdf" 8 9 def __init__(self,name,age): 10 self.name = name 11 self.age = age 12 13 # 方法:方法就是在類外面我們寫的函數,放在類里就叫做一個方法 14 def func(self): 15 c = 8 # 實例變數:定義在方法中的變數只作用於當前實例的類 16 print("Hello World!") 17 18 a = A() # 創建一個對象,實例化
上面的部分代碼還需要再解釋一下:
- object:
- 註意類名後面括弧里有個參數object,他代表所有類的基類,也叫作超類。
- 這就有了一個新式類和舊式類的概念:
- 當用到多繼承的時候,如果子類中沒有想用的方法名或屬性名,他會自動回到上面去找。那麼按廣度優先遍歷的方法去尋找就是新式類(object);深度優先(括弧里啥也沒有)。
- __init__():構造函數,實例化的時候若不顯示的定義,那麼預設調用一個無參的,是初始化的意思。
一、封裝
含義:對外面隱藏對象的屬性和方法,僅提供介面。
作用:安全性(通過私有變數改變對外的使用),復用性
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Student(object): 5 def __init__(self, name, score): 6 # 屬性僅前面有兩個下劃線代表私有變數,外部無法訪問,因此我們定義了兩個新的方法,這樣可以避免外部通過score亂改分數,僅當我們自己知道介面才可以修改 7 self.__name = name 8 self.__score = score 9 10 def info(self): 11 print('name: %s ; score: %d' % (self.__name,self.__score)) 12 13 def getScore(self): 14 return self.__score 15 16 def setScore(self, score): 17 self.__score = score 18 19 stu = Student('Tom',99) 20 print('修改前分數:',stu.getScore()) 21 stu.info() 22 stu.setScore(59) 23 print('修改後分數:',stu.getScore()) 24 stu.info()
封裝還是比較好理解的,不過其中還有一些,比如析構函數,重寫等等知識點最好在官方文檔過一遍。
二、繼承
2.1.1、含義
前面我們提到過,面向對象編程有個好處就是代碼復用,而其中一種方法就是通過繼承機制。繼承就是說定義的一個新類,繼承現有的類,獲得現有類的非私有屬性、方法。提到個私有,就是上面提到的那個前面加兩個下劃線的那個東西,他在外部無法調用,繼承他的子類也不能。被繼承的那個類稱為基類、父類或超類,子類也可以叫做派生類。
2.1.2、特點
1、在繼承中,基類的構造方法(__init__()方法)不會被自動調用,需要在子類的構造方法中專門調用。
2、在調用基類的方法時需要加上基類的類名首碼,並帶上self參數變數。區別於在類中調用普通函數時不需要帶self參數。
3、在python中,首先查找對應類型的方法,如果在子類中找不到對應的方法,才到基類中逐個查找。
2.2、單繼承
直接上代碼,仔細理解一下裡面的關係,我把講解都寫在註釋的地方。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 # 這是定義了一個基類 5 class Person(object): 6 def __init__(self, name, age, money): 7 self.name = name 8 self.age = age 9 self.__money = money # 私有屬性 10 # 被引入時,繼承不了,但他們的set,get函數可以繼承 11 12 def setMoney(self,money): 13 self.__money = money 14 15 def getMoney(self): 16 return self.__money 17 18 def run(self): 19 print("run") 20 21 def eat(self): 22 print("eat")
下麵是定義的一個子類,繼承自上方的類,來使用父類中的方法和屬性:
1 # 由於我將每個類寫在了不同的文件里,所以需要引入一下,這就和我們調用庫一樣 2 from 單繼承的實現.person import Person 3 4 class Student(Person): 5 def __init__(self,name,age,stuid,money): 6 # 調用父類中的__init__(),supper括弧中的內容,在python3以後可以不寫,寫上更安全些 7 super(Student,self).__init__(name,age,money) # 讓父類的self當做子類的對象 8 # 子類可以由一些自己獨有的屬性或者方法 9 self.stuid = stuid
創建對象,通過子類使用父類的屬性和方法:
1 from 單繼承的實現.student import Student 2 3 stu = Student('Tom',18,111,999) # 創建Student對象 4 # 下列方法和屬性均是在父類Person中定義的,在Student繼承之後,便可以直接使用 5 print(stu.name, stu.age) 6 stu.run() 7 print(stu.getMoney())
2.3、多繼承
上面的單繼承要多理解一下,單繼承理解了之後,多繼承也就沒什麼了。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Father(object): 5 def __init__(self,money): 6 self.money = money 7 def play(self): 8 print("play") 9 def func(self): 10 print("func1") 11 12 class Mother(object): 13 def __init__(self,facevalue): 14 self.facevalue = facevalue 15 def eat(self): 16 print("eat") 17 def func(self): 18 print("func2") 19 20 21 class Children(Father,Mother): 22 def __init__(self,money,facevalue): 23 # 多繼承時調用父類的屬性 24 Father.__init__(self,money) 25 Mother.__init__(self,facevalue) 26 27 def main(): 28 c = Children(300,100) 29 print(c.money,c.facevalue) 30 c.play() 31 c.eat() 32 # 註意:如果多個父類中有相同的方法名,預設調用括弧中前面的類 33 c.func() 34 if __name__ == "__main__": 35 main()View Code
三、多態
- 多態:是指一種事物的多種形態
- 多態性:多態性是指具有不同功能的函數可以使用相同的函數名,這樣就可以用一個函數名調用不同內容的函數。在面向對象方法中一般是這樣表述多態性:向不同的對象發送同一條消息,不同的對象在接收時會產生不同的行為(即方法)。也就是說,每個對象可以用自己的方式去響應共同的消息。所謂消息,就是調用函數,不同的行為就是指不同的實現,即執行不同的函數。
- eg:在python中的“+”號,它既可以表示數字的加法,也可以表示字元串的拼接,(__add__())
1 class Animal(object): 2 def __init__(self, name): 3 self.name = name 4 5 def run(self): 6 pass 7 8 def animalRun(self): 9 self.run() 10 11 12 class Cat(Animal): 13 def run(self): 14 print('cat is running') 15 16 17 class Dog(Animal): 18 def run(self): 19 print('dog is running') 20 21 22 d = Dog('dog') 23 c = Cat('cat') 24 25 Animal.animalRun(c) 26 Animal.animalRun(d)View Code
四、面向對象案例
下麵給一個小程式,是模擬反恐精英,保衛者和敵人。主要是讓大家看明白,只有簡單的幾個功能,希望大家可以從中理解面向對象的思想。python中,任何都是對象。
首先,這是我的幾個類模塊,分開來寫比較清晰一點,寫在一起也是沒問題的。接下來我們一點一點的分析:
。。。。。。。。。。
得有人,好人和壞人
。。。。。。。。。。
人得有武器,先給他們兩種:槍和手榴彈
。。。。。。。。。。
槍還有個彈夾也可以作為對象
。。。。。。。。。。
想想還有什麼,差不多了吧,那麼我們就開始寫,想到什麼再補充
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from cs.person import Person 5 6 class Gengster(Person): 7 8 # 初始化,血量預設為100 9 def __init__(self, gun, grenade, blood=100): 10 self.gun = gun 11 self.grenade = grenade 12 self.blood = blood 13 14 # 人有開槍的功能 15 def fire(self,person): 16 person.blood.amount -= 5 # 對誰開槍,那個人就要減血 17 self.gun.shoot() # 這個人開槍,這又調用了槍的類,關於子彈的減少在槍的類里 18 19 # 扔手榴彈,實際上是和槍一樣的 20 def fire2(self,person): 21 person.blood -= 10 22 self.grenade.damage() # 同樣通過另一個類來控制數量的減少,使代碼看起來簡潔點 23 24 # 給彈夾裡加子彈 25 def fillbullet(self): 26 self.gun.bulletbox.bulletcount += 10 27 28 # 補血,並保證滿血只能是100 29 def fillblood(self,num): 30 self.blood += num 31 if self.blood > 100: 32 self.blood = 100 33 print("補血後血量:" + str(self.blood))壞蛋
1 # 主要註釋和上一個類似,這裡不贅述 2 3 #!/usr/bin/env python 4 # -*- coding:utf-8 -*- 5 6 from cs.person import Person 7 8 class Profector(Person): 9 10 def __init__(self, gun, grenade, blood = 100): 11 self.gun = gun 12 self.grenade = grenade 13 self.blood = blood 14 15 def fire(self, person): 16 person.blood -= 5 17 self.gun.shoot() 18 print(str(person) + "血量減少5,剩餘" + str(person.blood) ) 19 20 def fire2(self,person): 21 person.blood -= 10 22 self.grenade.damage() 23 24 def fillbullet(self): 25 self.gun.bulletbox.bulletcount += 10 26 27 def fillblood(self,num): 28 self.blood += num 29 if self.blood > 100: 30 self.blood = 100 31 print("補血後血量:" + str(self.blood))好人
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Gun(object): 5 6 # 初始化,把彈夾放裡面,通過人來控制槍,再來控制彈夾 7 def __init__(self,bulletbox): 8 self.bulletbox = bulletbox 9 10 def shoot(self): 11 if self.bulletbox.bulletcount == 0: 12 print('沒子彈了') 13 else: 14 self.bulletbox.bulletcount -= 1 15 print(str(self) + '開一槍,還剩%d顆子彈' % (self.bulletbox.bulletcount))槍
1 # 與槍類似 2 3 #!/usr/bin/env python 4 # -*- coding:utf-8 -*- 5 6 class Grenade(object): 7 8 def __init__(self,grenadecount): 9 self.grenadecount = grenadecount 10 11 def damage(self): 12 if self.grenadecount == 0: 13 print('手雷沒有了') 14 else: 15 self.grenadecount -= 1 16 print(str(self) + "轟他一炮,手雷還剩%d顆" % (self.grenadecount))手榴彈
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Bulletbox(object): 5 6 # 彈夾只需控制數量就好了 7 def __init__(self,bulletcount): 8 self.bulletcount = bulletcount彈夾
這下差不多了,人也有了,武器也有了,可以開展了
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from cs.grenade import Grenade 5 from cs.gun import Gun 6 from cs.bulletbox import Bulletbox 7 from cs.gengster import Gengster 8 from cs.profector import Profector 9 # 參數:槍,手榴彈,血(預設100,且上限為100) 10 11 # 創建彈夾,槍,手榴彈的對象,以備人使用 12 bulletbox = Bulletbox(10) 13 gun = Gun(bulletbox) 14 grenade = Grenade(20) 15 16 # 創建人對象 17 good1 = Profector(gun,grenade) 18 good2 = Profector(gun,grenade) 19 bad1 = Gengster(gun,grenade) 20 bad2 = Gengster(gun,grenade) 21 22 print("好人1開槍打壞人1和2") 23 good1.fire(bad1) 24 good1.fire(bad2) 25 print("好人2開槍打壞人1和2") 26 good2.fire(bad1) 27 good2.fire(bad2) 28 print("壞人1炸好人1和2") 29 bad1.fire2(good1) 30 bad1.fire2(good2) 31 print("壞人2炸好人1和2") 32 bad2.fire2(good1) 33 bad2.fire2(good2) 34 print("壞人1補血3個") 35 bad1.fillblood(3)main
現在這一套流程就結束了,剛開始看也許看不太懂,要仔細看一下每個類之間的關係,先想清楚了,再來看代碼是如何實現的
有沒有看出來點區別,面向過程編程是就事論事,而面向對象,先把對象找出來,通過對象之間的關係把他們聯繫起來。想想如果要用面向過程來實現這個,代碼會寫成什麼樣子呢。
然而並沒有結束,記不記得前面的類中有兩對是比較類似的,好人和壞人,槍和手榴彈(這個裡面的類還不太一樣),那麼想到了什麼沒有,前面提到的繼承的優點是什麼來著,----復用。我們可以可以用繼承來寫一下呢,如果你說這個也沒少幾行代碼嘛,那麼,如果在實際當中你要創建成百上千的對象呢,難道還要每個都複製粘貼改代碼嗎,還占空間對不對。
那麼我們寫一個人類,畢竟好人和壞人都是人:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Person(object): 5 6 def __init__(self, gun, grenade, blood): 7 self.gun = gun 8 self.grenade = grenade 9 self.blood = blood 10 11 def fire(self, person): 12 person.blood -= 5 13 self.gun.shoot() 14 print(str(person) + "血量減少5,剩餘" + str(person.blood) ) 15 16 def fire2(self, person): 17 person.blood -= 10 18 self.grenade.damage() 19 print(str(person) + "血量減少10,剩餘" + str(person.blood) ) 20 21 def fillbullet(self): 22 self.gun.bulletbox.bulletcount += 10 23 24 def fillblood(self,num): 25 self.blood += num 26 if self.blood > 100: 27 self.blood = 100 28 print(str(self) + "補血後血量:" + str(self.blood))person
現在我們就不必把好人壞人都重寫了,只需要繼承一下人類就好了:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from cs.person import Person 5 6 class Profector(Person): 7 8 def __init__(self, gun, grenade, blood = 100): 9 super(Profector,self).__init__(gun, grenade, blood) 10 11 12 class Gengster(Person): 13 14 def __init__(self, gun, grenade, blood=100): 15 super(Gengster, self).__init__(gun, grenade, blood) 16 17 # 這裡面有個supper,他就是對父類的繼承好人和壞人
我知道大家看的有點迷了,我把他整在一起了,不過還是建議大家先根據每個小模塊學習,順便理解一下引入自定義模塊。下麵是完整代碼,可以直接粘貼:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Bulletbox(object): 5 def __init__(self,bulletcount): 6 self.bulletcount = bulletcount 7 8 9 class Gun(object): 10 def __init__(self,bulletbox): 11 self.bulletbox = bulletbox 12 13 def shoot(self): 14 if self.bulletbox.bulletcount == 0: 15 print('沒子彈了') 16 else: 17 self.bulletbox.bulletcount -= 1 18 print(str(self) + '開一槍,還剩%d顆子彈' % (self.bulletbox.bulletcount)) 19 20 21 class Grenade(object): 22 def __init__(self,grenadecount): 23 self.grenadecount = grenadecount 24 25 def damage(self): 26 if self.grenadecount == 0: 27 print('手雷沒有了') 28 else: 29 self.grenadecount -= 1 30 print(str(self) + "轟他一炮,手雷還剩%d顆" % (self.grenadecount)) 31 32 33 class Person(object): 34 def __init__(self, gun, grenade, blood): 35 self.gun = gun 36 self.grenade = grenade 37 self.blood = blood 38 39 def fire(self, person): 40 person.blood -= 5 41 self.gun.shoot() 42 print(str(person) + "血量減少5,剩餘" + str(person.blood) ) 43 44 def fire2(self, person): 45 person.blood -= 10 46 self.grenade.damage() 47 print(str(person) + "血量減少10,剩餘" + str(person.blood) ) 48 49 def fillbullet(self): 50 self.gun.bulletbox.bulletcount += 10 51 52 def fillblood(self,num): 53 self.blood += num 54 if self.blood > 100: 55 self.blood = 100 56 print(str(self) + "補血後血量:" + str(self.blood)) 57 58 59 class Profector(Person): 60 def __init__(self, gun, grenade, blood = 100): 61 super(Profector,self).__init__(gun, grenade, blood) 62 63 64 class Gengster(Person): 65 def __init__(self, gun, grenade, blood=100): 66 super(Gengster, self).__init__(gun, grenade, blood) 67 68 69 bulletbox = Bulletbox(10) 70 gun = Gun(bulletbox) 71 grenade = Grenade(20) 72 73 good1 = Profector(gun,grenade) 74 good2 = Profector(gun,grenade) 75 bad1 = Gengster(gun,grenade) 76 bad2 = Gengster(gun,grenade) 77 78 print("