python08-面向物件程式設計基礎
面向物件程式設計(Object Oriented Programming, OOP),物件中包含了資料與對資料進行操作的方法。python中自定義的物件即是類(class),類定義的一個個實體叫做例項(instance)。
1 類與例項
>>> class lover(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
def print_lover(self):
print('%s %s'%(self.__name,self.__age))
>>> lover1 = lover('sui',20)
1.1 類的定義形式為
class+類名+()
()中的內容是該類需要繼承的類,如果沒有的話就寫object,因為所有類都要繼承這個類。
1.2 顯而易見,在類中定義的函式的第一個引數一定是self,但是在呼叫函式的不用傳該引數,因為python會自動把當前例項傳進去。
1.3 第一個函式__init__
是類的初始化,定義了類的屬性(property),在建立例項的時候必須傳進與__init__
函式相對用的引數,否則將報錯。
1.4 在Python中,例項的變數名如果以__
(雙下劃線)開頭,就變成了一個私有變數(private),只有內部可以訪問,外部不能訪問。比如在上邊定義的name屬性和age屬性都使用了雙下劃線開頭,這時候再在外部使用 lover1.__name
__xxx__
的,也就是以雙下劃線開頭,並且以雙下劃線結尾的,是特殊變數,特殊變數是可以直接訪問的,不是private變數,所以,不能用__name__
、__score__
這樣的變數名。
有些時候,你會看到以一個下劃線開頭的例項變數名,比如_name,這樣的例項變數外部是可以訪問的,但是,按照約定俗成的規定,當你看到這樣的變數時,意思就是,“雖然我可以被訪問,但是,請把我視為私有變數,不要隨意訪問”。(廖雪峰)
1.5 例項的定義方法非常簡單, 例項名=類名+(屬性值)
1.6 還有一點就是,對於python這種動態語言來說,不同的例項可以繫結不同的屬性或方法,比如我定義了兩個例項:
lover1 = lover(‘sui’,20)
lover2 = lover(‘sun’,18)
我可以給lover1多繫結一個gender屬性,而lover2則沒有該屬性。
>>>lover1.gender = ‘male’
>>> lover1.gender
'male'
>>> lover2.gender
Traceback (most recent call last):
File "<pyshell#33>", line 1, in <module>
lover2.gender
AttributeError: 'lover' object has no attribute 'gender'
2 繼承
繼承呢,簡單說就是:你爸的東西是你的,但是你的不一定是你爸的。
繼承的類叫做子類(subclass),被繼承的類叫做父類或是基類(base class)。子類將擁有父類的所有屬性和方法。但是如果子類中定義了與父類相同的方法,那麼有效的是子類的,也就是說完成了覆蓋。
舉例如下:
>>> class Animal(object):
def print_run(self):
print('Animal is running.')
>>> class Dog(Animal):
pass
>>> class Cat(Animal):
pass
Dog和Cat都是Animal的子類,儘管他們的定義中什麼都沒有,但是將會繼承父類Animal的print_run函式。
>>> cat = Cat()
>>> dog = Dog()
>>> dog.print_run()
Animal is running.
>>> cat.print_run()
Animal is running.
如果改寫一下Dog類的內容,給他也定義一個print_run方法,則:
>>> class Dog(Animal):
def print_run(self):
print('Dog is runnning')
>>> dog = Dog()
>>> dog.print_run()
Dog is runnning
可見,現在變成Dog is running了,子類的方法覆蓋了父類。
3 多型
經過前面的繼承以後,有一個小問題,例項dog的資料型別是Dog
>>> isinstance(dog,Dog)
True
那麼isinstance(dog,Animal)
的結果是什麼呢?結果是 True
所以說子類的例項的資料型別不僅可以是本身,也可以是父類。
這樣就產生了多型的這個概念:同一個實現介面,使用不同的例項而執行不同的操作。
多型的實現步驟一般是:
- 寫一個方法,它只接收父類作為引數,編寫的程式碼只與父類打交道。
- 子類重寫父類的方法。使子類具有不同的方法實現。
- 執行時,根據實際建立的物件型別動態決定使用那個方法。
下面進行舉例:
首先寫一個函式,他的引數是一個父類:
>>> def something_run(Animal):
Animal.print_run()
由於在前面已經為Dog和Cat都重寫了print_run方法,所以直接實驗。
>>> ani = Animal()
>>> something_run(ani)
Animal is running.
>>> something_run(dog)
Dog is running
所以可見多型的好處就是,函式是不用做修改的,只需要重寫每個子類的方法就好了。使程式碼簡潔易修改。
其實,對於python來說,傳入的引數甚至不用是Animal或是Animal的子類都可以,只要你這個類中有print_run這個方法就可以了。這被稱為“鴨子型別”,這是動態語言的特點!