1. 程式人生 > >python08-面向物件程式設計基礎

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

就會報錯。需要注意的是,在Python中,變數名類似__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
所以說子類的例項的資料型別不僅可以是本身,也可以是父類。

這樣就產生了多型的這個概念:同一個實現介面,使用不同的例項而執行不同的操作。

多型的實現步驟一般是:

  1. 寫一個方法,它只接收父類作為引數,編寫的程式碼只與父類打交道。
  2. 子類重寫父類的方法。使子類具有不同的方法實現。
  3. 執行時,根據實際建立的物件型別動態決定使用那個方法。

下面進行舉例:
首先寫一個函式,他的引數是一個父類:

>>> 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這個方法就可以了。這被稱為“鴨子型別”,這是動態語言的特點!