面向過程 VS 面向對象 編程範式 編程是程式員用特定的語法+數據結構+演算法組成的代碼來告訴電腦如何執行任務的過程,一個程式是程式員為了得到一個任務結果而編寫的一組指令的集合,正所謂條條大路通羅馬,實現一個任務的方式有很多種不同的方式, 對這些不同的編程方式的特點進行歸納總結得出來的編程方式類別, ...
面向過程 VS 面向對象
編程範式
編程是程式員用特定的語法+數據結構+演算法組成的代碼來告訴電腦如何執行任務的過程,一個程式是程式員為了得到一個任務結果而編寫的一組指令的集合,正所謂條條大路通羅馬,實現一個任務的方式有很多種不同的方式, 對這些不同的編程方式的特點進行歸納總結得出來的編程方式類別,即為編程範式。 不同的編程範式本質上代表對各種類型的任務採取的不同的解決問題的思路, 大多數語言只支持一種編程範式,當然也有些語言可以同時支持多種編程範式。 兩種最重要的編程範式分別是面向過程編程和面向對象編程:
面向過程編程(Procedural Programming)
Procedural programming uses a list of instructions to tell the computer what to do step-by-step.
面向過程編程依賴 - 你猜到了- procedures,一個procedure包含一組要被進行計算的步驟, 面向過程又被稱為top-down languages, 就是程式從上到下一步步執行,一步步從上到下,從頭到尾的解決問題 。基本設計思路就是程式一開始是要著手解決一個大的問題,然後把一個大問題分解成很多個小問題或子過程,這些子過程再執行的過程再繼續分解直到小問題足夠簡單到可以在一個小步驟範圍內解決。
舉個典型的面向過程的例子, 資料庫備份, 分三步,連接資料庫,備份資料庫,測試備份文件可用性。
代碼如下
def db_conn(): print("connecting db...") #第一步 def db_backup(dbname): print("導出資料庫...", dbname) #第二部到處資料庫 print("將備份文件打包,移至相應目錄...") #第三部將文件備份 def db_backup_test(): print("將備份文件導入測試庫,看導入是否成功") def main(): db_conn() db_backup('my_db') db_backup_test() if __name__ == "__main__": main()
運行結果如下:
connecting db...
導出資料庫... my_db
將備份文件打包,移至相應目錄...
將備份文件導入測試庫,看導入是否成
上面代碼就是一個面向過程的典型案例,面向對象就是,一個程式,一步一步往下來,具有很強的邏輯性,這種事情在現實社會中也有很多情況。
這樣做的問題也是顯而易見的,就是如果你要對程式進行修改,對你修改的那部分有依賴的各個部分你都也要跟著修改,舉個例子,如果程式開頭你設置了一個變數值為1,但如果其它子過程依賴這個值為1的變數才能正常運行,那如果你改了這個變數,那這個子過程你也要修改,假如又有一個其它子程式依賴這個子過程,那就會發生一連串的影響,隨著程式越來越大,這種編程方式的維護難度會越來越高。
所以我們一般認為, 如果你只是寫一些簡單的腳本,去做一些一次性任務,用面向過程的方式是極好的,但如果你要處理的任務是複雜的,且需要不斷迭代和維護的, 那還是用面向對象最方便了。
面向對象編程
OOP編程是利用“類”和“對象”來創建各種模型來實現對真實世界的描述,使用面向對象編程的原因一方面是因為它可以使程式的維護和擴展變得更簡單,並且可以大大提高程式開發效率 ,另外,基於面向對象的程式可以使它人更加容易理解你的代碼邏輯,從而使團隊開發變得更從容。
面向對象的幾個核心特性如下:
Class 類
一個類即是對一類擁有相同屬性的對象的抽象、藍圖、原型。在類中定義了這些對象的都具備的屬性(variables(data))、共同的方法。
Object 對象
一個對象即是一個類的實例化後實例,一個類必須經過實例化後方可在程式中調用,一個類可以實例化多個對象,每個對象亦可以有不同的屬性,就像人類是指所有人,每個人是指具體的對象,人與人之前有共性,亦有不同。
Encapsulation 封裝
在類中對數據的賦值、內部調用對外部用戶是透明的,這使類變成了一個膠囊或容器,裡面包含著類的數據和方法
Inheritance 繼承
一個類可以派生出子類,在這個父類里定義的屬性、方法自動被子類繼承
Polymorphism 多態
多態是面向對象的重要特性,簡單點說:“一個介面,多種實現”,指一個基類中派生出了不同的子類,且每個子類在繼承了同樣的方法名的同時又對父類的方法做了不同的實現,這就是同一種事物表現出的多種形態。
編程其實就是一個將具體世界進行抽象化的過程,多態就是抽象化的一種體現,把一系列具體事物的共同點抽象出來, 再通過這個抽象的事物, 與不同的具體事物進行對話。
對不同類的對象發出相同的消息將會有不同的行為。比如,你的老闆讓所有員工在九點鐘開始工作, 他只要在九點鐘的時候說:“開始工作”即可,而不需要對銷售人員說:“開始銷售工作”,對技術人員說:“開始技術工作”, 因為“員工”是一個抽象的事物, 只要是員工就可以開始工作,他知道這一點就行了。至於每個員工,當然會各司其職,做各自的工作。
多態允許將子類的對象當作父類的對象使用,某父類型的引用指向其子類型的對象,調用的方法是該子類型的方法。這裡引用和調用方法的代碼編譯前就已經決定了,而引用所指向的對象可以在運行期間動態綁定。
面向對象編程(Object-Oriented Programming )介紹
對於編程語言的初學者來講,OOP不是一個很容易理解的編程方式,大家雖然都按老師講的都知道OOP的三大特性是繼承、封裝、多態,並且大家也都知道瞭如何定義類、方法等面向對象的常用語法,但是一到真正寫程式的時候,還是很多人喜歡用函數式編程來寫代碼,特別是初學者,很容易陷入一個窘境就是“我知道面向對象,我也會寫類,但我依然沒發現在使用了面向對象後,對我們的程式開發效率或其它方面帶來什麼好處,因為我使用函數編程就可以減少重覆代碼並做到程式可擴展了,為啥子還用面向對象?”。 對於此,我個人覺得原因應該還是因為你沒有充分瞭解到面向對象能帶來的好處,今天我就寫一篇關於面向對象的入門文章,希望能幫大家更好的理解和使用面向對象編程。
無論用什麼形式來編程,我們都要明確記住以下原則:
(1)寫重覆代碼是非常不好的低級行為
(2)你寫的代碼需要經常變更
開發正規的程式跟那種寫個運行一次就扔了的小腳本一個很大不同就是,你的代碼總是需要不斷的更改,不是修改bug就是添加新功能等,所以為了日後方便程式的修改及擴展,你寫的代碼一定要遵循易讀、易改的原則(專業數據叫可讀性好、易擴展)。
如果你把一段同樣的代碼複製、粘貼到了程式的多個地方以實現在程式的各個地方調用這個功能,那日後你再對這個功能進行修改時,就需要把程式里多個地方都改一遍,這種寫程式的方式是有問題的,因為如果你不小心漏掉了一個地方沒改,那可能會導致整個程式的運行都出問題。 因此我們知道在開發中一定要努力避免寫重覆的代碼,否則就相當於給自己再挖坑。
還好,函數的出現就能幫我們輕鬆的解決重覆代碼的問題,對於需要重覆調用的功能,只需要把它寫成一個函數,然後在程式的各個地方直接調用這個函數名就好了,並且當需要修改這個功能時,只需改函數代碼,然後整個程式就都更新了。
其實OOP編程的主要作用也是使你的代碼修改和擴展變的更容易,那麼小白要問了,既然函數都能實現這個需求了,還要OOP乾毛線用呢? 呵呵,說這話就像,古時候,人們打仗殺人都用刀,後來出來了槍,它的主要功能跟刀一樣,也是殺人,然後小白就問,既然刀能殺人了,那還要槍乾毛線,哈哈,顯而易見,因為槍能更好更快更容易的殺人。函數編程與OOP的主要區別就是OOP可以使程式更加容易擴展和易更改。
小白說,我讀書少,你別騙我,口說無憑,證明一下,好吧,那我們就下麵的例子證明給小白看。
相信大家都打過CS游戲吧,我們就自己開發一個簡單版的CS來玩一玩。
暫不考慮開發場地等複雜的東西,我們先從人物角色下手, 角色很簡單,就倆個,恐怖份子、警察,他們除了角色不同,其它基本都 一樣,每個人都有生命值、武器等。 咱們先用非OOP的方式寫出游戲的基本角色。
# role 1 name = 'Alex' role = 'terrorist' weapon = 'AK47' life_value = 100 # rolw 2 name2 = 'Jack' role2 = 'police' weapon2 = 'B22' life_value2 = 100
上面定義了一個恐怖份子Alex和一個警察Jack,但只2個人不好玩呀,一干就死了,沒意思,那我們再分別一個恐怖分子和警察吧!
# role 1 name = 'Alex' role = 'terrorist' weapon = 'AK47' life_value = 100 money = 10000 # rolw 2 name2 = 'Jack' role2 = 'police' weapon2 = 'B22' life_value2 = 100 money2 = 10000 # role 3 name3 = 'Rain' role3 = 'terrorist' weapon3 = 'C33' life_value3 = 100 money3 = 10000 # rolw 4 name4 = 'Eric' role4 = 'police' weapon4 = 'B51' life_value4 = 100 money4 = 10000
4個角色雖然創建好了,但是有個問題就是,每創建一個角色,我都要單獨命名,name1,name2,name3,name4…,後面的調用的時候這個變數名你還都得記著,要是再讓多加幾個角色,估計調用時就很容易弄混啦,所以我們想一想,能否所有的角色的變數名都是一樣的,但調用的時候又能區分開分別是誰?
當然可以,我們只需要把上面的變數改成字典的格式就可以啦!
roles = { 1: {'name': 'Alex', 'role': 'terrorist', 'weapon': 'AK47', 'life_value': 100, 'money': 15000, }, 2: {'name': 'Jack', 'role': 'police', 'weapon': 'B22', 'life_value': 100, 'money': 15000, }, 3: {'name': 'Rain', 'role': 'terrorist', 'weapon': 'C33', 'life_value': 100, 'money': 15000, }, 4: {'name': 'Eirc', 'role': 'police', 'weapon': 'B51', 'life_value': 100, 'money': 15000, }, } print(roles[1]) # Alex print(roles[2]) # Jack
代碼運行如下:
{'life_value': 100, 'name': 'Alex', 'role': 'terrorist', 'weapon': 'AK47', 'money': 15000}
{'life_value': 100, 'name': 'Jack', 'role': 'police', 'weapon': 'B22', 'money': 15000}
很好,這個以後調用這些角色時只需要roles[1],roles[2]就可以啦,角色的基本屬性設計完了後,我們接下來為每個角色開發以下幾個功能:
1.被打中後就會掉血的功能
2.開槍功能
3.換子彈
4.買槍
5.跑、走、跳、下蹲等動作
6.保護人質3(僅適用於警察)
7.不能殺同伴
8.......
我們可以把每個功能寫成一個函數,類似如下:
def shot(by_who): #開了槍後要減子彈數 pass def got_shot(who): #中槍後要減血 who[‘life_value’] -= 10 pass def buy_gun(who,gun_name): #檢查錢夠不夠,買了槍後要扣錢 pass ...
so far so good, 繼續按照這個思路設計,再完善一下代碼,游戲的簡單版就出來了,但是在往下走之前,我們來看看上面的這種代碼寫法有沒有問題,至少從上面的代碼設計中,我看到以下幾點缺陷:
(1)每個角色定義的屬性名稱是一樣的,但這種命名規則是我們自己約定的,從程式上來講,並沒有進行屬性合法性檢測,也就是說role 1定義的代表武器的屬性是weapon, role 2 ,3,4也是一樣的,不過如果我在新增一個角色時不小心把weapon 寫成了wepon , 這個程式本身是檢測不到的;
(2)terrorist 和police這2個角色有些功能是不同的,比如police是不能殺人質的,但是terrorist可能,隨著這個游戲開發的更複雜,我們會發現這2個角色後續有更多的不同之處, 但現在的這種寫法,我們是沒辦法 把這2個角色適用的功能區分開來的,也就是說,每個角色都可以直接調用任意功能,沒有任何限制;
(3)我們在上面定義了got_shot()後要減血,也就是說減血這個動作是應該通過被擊中這個事件來引起的,我們調用get_shot(),got_shot()這個函數再調用每個角色里的life_value變數來減血。 但其實我不通過got_shot(),直接調用角色roles[role_id][‘life_value’] 減血也可以呀,但是如果這樣調用的話,那可以就是簡單粗暴啦,因為減血之前其它還應該判斷此角色是否穿了防彈衣等,如果穿了的話,傷害值肯定要減少,got_shot()函數里就做了這樣的檢測,你這裡直接繞過的話,程式就亂了。 因此這裡應該設計 成除了通過got_shot(),其它的方式是沒有辦法給角色減血的,不過在上面的程式設計里,是沒有辦法實現的;
(4)現在需要給所有角色添加一個可以穿防彈衣的功能,那很顯然你得在每個角色里放一個屬性來存儲此角色是否穿 了防彈衣,那就要更改每個角色的代碼,給添加一個新屬性,這樣太low了,不符合代碼可復用的原則。
上面這4點問題如果不解決,以後肯定會引出更大的坑,有同學說了,解決也不複雜呀,直接在每個功能調用時做一下角色判斷啥就好了,沒錯,你要非得這麼霸王硬上弓的搞也肯定是可以實現的,那你自己就開發相應的代碼來對上面提到的問題進行處理好啦。 但這些問題其實能過OOP就可以很簡單的解決。
之前的代碼改成用OOP中的“類”來實現的話如下:
class Role(object): def __init__(self, name, role, weapon, life_value=100, money=15000): self.name = name self.role = role self.weapon = weapon self.life_value = life_value self.money = money def shot(self): print("shooting...") def got_shot(self): print("ah...,I got shot...") def buy_gun(self, gun_name): print("just bought %s" % gun_name) r1 = Role('Alex','police',"AK47") #生成一個警察的角色 r2 = Role('Jack', 'terrorist',"B22") #生成一個恐怖分子的角色
先不考慮語法細節,相比靠函數拼湊出來的寫法,上面用面向對象中的類來寫最直接的改進有以下2點:
(1)代碼量少了近一半
(2)角色和它所具有的功能可以一目瞭然看出來
在真正開始分解上面代碼含義之之前,我們現來瞭解一些類的基本定義
類的語法
class Dog(object):
print("hello,I am a dog!")
d = Dog() # 實例化這個類,
# 此時的d就是類Dog的實例化對象
# 實例化,其實就是以Dog類為模版,在記憶體里開闢一塊空間,存上數據,賦值成一個變數名
上面的代碼其實有問題,想給狗起名字傳不進去。
class Dog(object): def __init__(self, name, dog_type): self.name = name self.dog_type = dog_type def sayhi(self): print("hello,I am a dog, my name is ", self.name) d = Dog('LiChuang', "京巴") d.sayhi()
運行結果如下:
hello,I am a dog, my name is LiChuang
上面代碼中,我們定義了一個Dog類,並且可以傳遞參數,這樣我們就可以以我們的方式傳遞參數。
為什麼有__init__? 為什麼有self? 此時的你一臉蒙逼,相信不畫個圖,你的智商是理解不了的!
畫圖之前, 你先註釋掉這兩句:
d = Dog('LiChuang', "京巴"
)
d.sayhi()
print
(Dog)
沒實例直接列印Dog輸出如下:
<class '__main__.Dog'>
這代表什麼?代表即使不實例化,這個Dog類本身也是已經存在記憶體里的對不對, yes, cool,那實例化時,會產生什麼化學反應呢?
根據上圖我們得知,其實self,就是實例本身!你實例化時python會自動把這個實例本身通過self參數傳進去。
self就是我們創建的本身實例,讓實例具有類中所有的屬性和方法,以便我們調用的時候可以直接調用,方便我們操作。
class Role(object): #定義一個類, class是定義類的語法,Role是類名,(object)是新式類的寫法,必須這樣寫,以後再講為什麼 def __init__(self,name,role,weapon,life_value=100,money=15000): #初始化函數,在生成一個角色時要初始化的一些屬性就填寫在這裡 self.name = name #__init__中的第一個參數self,和這裡的self都 是什麼意思? 看下麵解釋 self.role = role self.weapon = weapon self.life_value = life_value self.money = money
上面的這個__init__()叫做初始化方法(或構造方法), 在類被調用時,這個方法(雖然它是函數形式,但在類中就不叫函數了,叫方法)會自動執行,進行一些初始化的動作,所以我們這裡寫的__init__(self,name,role,weapon,life_value=100,money=15000)就是要在創建一個角色時給它設置這些屬性,那麼這第一個參數self是乾毛用的呢?
初始化一個角色,就需要調用這個類一次:
class Role(object): #定義一個類, class是定義類的語法,Role是類名,(object)是新式類的寫法,必須這樣寫,以後再講為什麼 def __init__(self,name,role,weapon,life_value=100,money=15000): #初始化函數,在生成一個角色時要初始化的一些屬性就填寫在這裡 self.name = name #__init__中的第一個參數self,和這裡的self都 是什麼意思? 看下麵解釋 self.role = role self.weapon = weapon self.life_value = life_value self.money = money r1 = Role('Alex','police',"AK47") #生成一個角色 , 會自動把參數傳給Role下麵的__init__(...)方法 r2 = Role('Jack','terrorist',"B22") #生成一個角色 print(r1) print(r2) 運行結果如下: <__main__.Role object at 0x7fd630f63278> <__main__.Role object at 0x7fd630f632b0>
我們看到,上面的創建角色時,我們並沒有給__init__傳值,程式也沒未報錯,是因為,類在調用它自己的__init__(…)時自己幫你給self參數賦值了。
r1 = Role('Alex','police','AK47’) #此時self 相當於 r1 , Role(r1,'Alex','police','AK47’)
r2 = Role('Jack','terrorist','B22’) #此時self 相當於 r2, Role(r2,'Jack','terrorist','B22’)
為什麼這樣子?你拉著我說你有些猶豫,怎麼會這樣子?
你執行r1 = Role('Alex','police','AK47’)時,python的解釋器其實幹了兩件事:
(1)在記憶體中開闢一塊空間指向r1這個變數名;
(2)調用Role這個類並執行其中的__init__(…)方法,相當於Role.__init__(r1,'Alex','police',’AK47’),這麼做是為什麼呢? 是為了把'Alex','police',’AK47’這3個值跟剛開闢的r1關聯起來,是為了把'Alex','police',’AK47’這3個值跟剛開闢的r1關聯起來,是為了把'Alex','police',’AK47’這3個值跟剛開闢的r1關聯起來,重要的事情說3次, 因為關聯起來後,你就可以直接r1.name, r1.weapon 這樣來調用啦。所以,為實現這種關聯,在調用__init__方法時,就必須把r1這個變數也傳進去,否則__init__不知道要把那3個參數跟誰關聯呀!
(3)明白了麽哥?所以這個__init__(…)方法里的,self.name = name,self.role = role等等的意思就是要把這幾個值存到r1的記憶體空間里。
好啦, 總結一下2點:
(1)上面的這個r1 = Role('Alex','police','AK47’)動作,叫做類的“實例化”, 就是把一個虛擬的抽象的類,通過這個動作,變成了一個具體的對象了, 這個對象就叫做實例;
(2)剛纔定義的這個類體現了面向對象的第一個基本特性,封裝,其實就是使用構造方法將內容封裝到某個具體對象中,然後通過對象直接或者self間接獲取被封裝的內容。
面向對象的特性:
(1)封裝:
封裝最好理解了。封裝是面向對象的特征之一,是對象和類概念的主要特性;
封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。
class Role(object): #定義一個類, class是定義類的語法,Role是類名,(object)是新式類的寫法,必須這樣寫,以後再講為什麼 ac = None #類的屬性 def __init__(self,name,role,weapon,life_value=100,money=15000): #初始化函數,在生成一個角色時要初始化的一些屬性就填寫在這裡 self.name = name #__init__中的第一個參數self,和這裡的self都 是什麼意思? 看下麵解釋 self.role = role self.weapon = weapon self.life_value = life_value self.money = money def shot(self,name): print("I shoting your") #可以通過r1.name創建新的實例變數r1.name等價於r1.name = name r1 = Role("alex","police","AK4 7") r2 = Role("peiqi","police","B11") print(r1.ac) r1.ac = "USA Brand" #成員屬性,可以創建成員屬性,在調用的時候產生 print(r1.ac) Role.weapon = "B110" Role.ac = "Janpase Brand" #類裡面的變數,修改類的變數不會影響實例變數 t1 = Role("aoi","torrest","B520") t2 = Role("marry","torrest","Bsb") print(t2.ac) print(t2.weapon)
上面代碼體現了類變數和實例變數的情況,類變數屬於類本身的屬性;而實例變數在記憶體中單獨存在,我們可以通過實例名d.name重新創建一個實例變數,d.name等價於d.name = name。
(2)繼承:
面向對象編程 (OOP) 語言的一個主要功能就是“繼承”。繼承是指這樣一種能力:它可以使用現有類的所有功能,併在無需重新編寫原來的類的情況下對這些功能進行擴展;
通過繼承創建的新類稱為“子類”或“派生類”;
被繼承的類稱為“基類”、“父類”或“超類”;
繼承的過程,就是從一般到特殊的過程;
要實現繼承,可以通過“繼承”(Inheritance)和“組合”(Composition)來實現。
在某些 OOP 語言中,一個子類可以繼承多個基類。但是一般情況下,一個子類只能有一個基類,要實現多重繼承,可以通過多級繼承來實現。
繼承概念的實現方式主要有2類:實現繼承、介面繼承。
(1)實現繼承是指使用基類的屬性和方法而無需額外編碼的能力;
(2)介面繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現的能力(子類重構爹類方法);
在考慮使用繼承時,有一點需要註意,那就是兩個類之間的關係應該是“屬於”關係。例如,Employee 是一個人,Manager 也是一個人,因此這兩個類都可以繼承 Person 類。但是 Leg 類卻不能繼承 Person 類,因為腿並不是一個人。
抽象類僅定義將由子類創建的一般屬性和方法。
OO開發範式大致為:劃分對象→抽象類→將類組織成為層次化結構(繼承和合成) →用類與實例進行設計和實現幾個階段。
繼承示例:
#創建一個繼承類,繼承就是父類是公共屬性,子類是細化屬性 #定義一個學校成員類,教師類、學生類 #學生類,教師類繼承學校成員類 class SchoolMember(object): nums = 0 #學校成員數量,註冊之後人數加一 def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex self.enroll() #初始化之後,就數量加一 def enroll(self): SchoolMember.nums += 1 print("\033[32;1mSchool member [%s] has enrolled,now there are [%s] school menbers.\033[0m" %(self.name,SchoolMember.nums)) def tell(self): print("My name is %s." %self.name) class Teacther(SchoolMember): def __init__(self,name,age,sex,course,salary): super(Teacther,self).__init__(name,age,sex) self.course = course self.salary = salary def teaching(self): print("Teacher [%s] teach [%s]." %(self.name,self.course)) class Student(SchoolMember): def __init__(self,name,age,sex,course,tuition): super(Student,self).__init__(name,age,sex) self.course = course self.tuition = tuition def pay_tuition(self): print("Cao,student [%s] need to pay tuition [%s]." %(self.name,self.tuition)) t1 = Teacther("alex","22","F","python","10000") t2 = Teacther("tenglan","25","N/A","python","80000") s1 = Student("sanjiang","24","Female","python",15000) s2 = Student("Baoan","28","Female","python",5000)
上面實例就是繼承的標準情況,我們定義一個父類,父類具有子類所需的公共屬性,寫父類的目的是為了減少代碼的重用,子類具有父類的一切屬性和方法,上面父類SchoolMember,子類是Teacther和Student繼承了父類SchoolMember,擁有父類的屬性;\033[num;1m \033[0m是給程式輸出進行著色。
class SchoolMember(object): members = 0 # 初始學校人數為0 def __init__(self, name, age): self.name = name self.age = age def tell(self): pass def enroll(self): '''註冊''' SchoolMember.members += 1 print("\033[32;1mnew member [%s] is enrolled,now there are [%s] members.\033[0m " % ( self.name, SchoolMember.members)) def __del__(self): '''析構方法''' print("\033[31;1mmember [%s] is dead!\033[0m" % self.name) class Teacher(SchoolMember): def __init__(self, name, age, course, salary): super(Teacher, self).__init__(name, age) self.course = course self.salary = salary self.enroll() def teaching(self): '''講課方法''' print("Teacher [%s] is teaching [%s] for class [%s]" % (self.name, self.course, 's12')) def tell(self): '''自我介紹方法''' msg = '''Hi, my name is [%s], works for [%s] as a [%s] teacher !''' % (self.name, 'Oldboy', self.course) print(msg) class Student(SchoolMember): def __init__(self, name, age, grade, sid): super(Student, self).__init__(name, age) self.grade = grade self.sid = sid self.enroll() def tell(self): '''自我介紹方法''' msg = '''Hi, my name is [%s], I'm studying [%s] in [%s]!''' % (self.name, self.grade, 'Oldboy') print(msg) if __name__ == '__main__': t1 = Teacher("Alex", 22, 'Python', 20000) t2 = Teacher("TengLan", 29, 'Linux', 3000) s1 = Student("Qinghua", 24, "Python S12", 1483) s2 = Student("SanJiang", 26, "Python S12", 1484) t1.teaching() t2.teaching() t1.tell() t1.enroll() t2.enroll()
多態
多態性(polymorphisn)是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之後,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。 那麼,多態的作用是什麼呢?我們知道,封裝可以隱藏實現細節,使得代碼模塊化;繼承可以擴展已存在的代碼模塊(類);它們的目的都是為了——代碼重用。而多態則是為了