標籤:object star 展開 動態 code dog ima 靜態 ...
一、繼承
1 class Animal(object): 2 def run(self): 3 print(‘Animal is running...‘) 4 5 class Dog(Animal): 6 7 def run(self): 8 print(‘Dog is running...‘) 9 10 def eat(self):11 print(‘Eating meat...‘)12 13 dog = Dog()14 dog.run()
1 Dog is running...
當子類和父類都存在相同的run()方法時,我們說,子類的run()覆蓋了父類的run(),在代碼啟動並執行時候,總是會調用子類的run()。
二、多態
當我們定義一個class的時候,我們實際上就定義了一種資料類型。
1 >>>a = list()2 >>>b = Animal()3 >>>c = Dog()4 >>> isinstance(a, list)5 True6 >>> isinstance(b, Animal)7 True8 >>> isinstance(c, Dog)9 True
1 >>> isinstance(c, Animal)2 True
看來c不僅僅是Dog,c還是Animal!所以,在繼承關係中,如果一個執行個體的資料類型是某個子類,那它的資料類型也可以被看做是父類。
1 >>> class Animal(object): 2 ... def run(self): 3 ... print(‘Animal is running...‘) 4 ... 5 >>> class Dog(Animal): 6 ... def run(self): 7 ... print(‘Dog is running...‘) 8 ... 9 >>> class Cat(Animal):10 ... def run(self):11 ... print(‘Cat is running...‘)12 ... 13 >>> def run_twice(animal):14 ... animal.run()15 ... animal.run()16 ... 17 >>> run_twice(Animal())18 Animal is running...19 Animal is running...20 >>> run_twice(Dog())21 Dog is running...22 Dog is running...23 >>> run_twice(Cat())24 Cat is running...25 Cat is running...26 >>> class Dark(Animal):27 ... def run(self):28 ... print(‘Dark is running‘)29 ... 30 >>> run_twice(Dark())31 Dark is running32 Dark is running
“開閉”原則:
對擴充開放:允許新增Animal子類;
對修改封閉:不需要修改依賴Animal類型的run_twice()等函數。
三、靜態語言和動態語言
對於靜態語言(例如Java)來說,如果需要傳入Animal類型,則傳入的對象必須是Animal類型或者它的子類,否則,將無法調用run()方法。
對於Python這樣的動態語言來說,則不一定需要傳入Animal類型。我們只需要保證傳入的對象有一個run()方法就可以了:
1 class Timer(object):2 def run(self):3 print(‘Start...‘)
這就是動態語言的“鴨子類型”,它並不要求嚴格的繼承體系,一個對象只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子。
Python的“file-like object“就是一種鴨子類型。對真正的檔案對象,它有一個read()方法,返回其內容。但是,許多個物件,只要有read()方法,都被視為“file-like object“。許多函數接收的參數就是“file-like object“,你不一定要傳入真正的檔案對象,完全可以傳入任何實現了read()方法的對象。
動態語言的鴨子類型特點決定了繼承不像靜態語言那樣是必須的。
python 物件導向四 繼承和多態