[ python ] 多態

python天生支持多態python

多態指的是一類事物有多種形態函數

當咱們定義一個class的時候,咱們實際上就定義了一種數據類型,咱們定義的數據類型和python自帶的數據類型,好比str、list、dict 沒什麼兩樣:spa

In [1]: class Animal:
   ...:     pass

In [2]: class Dog(Animal):
   ...:     pass

In [3]: a = list()

In [4]: b = Animal()

In [5]: c = Dog()

In [6]: isinstance(a, list)    # a 是 list 類型
Out[6]: True

In [7]: isinstance(b, Animal)    # b 是 Animal 類型
Out[7]: True

In [8]: isinstance(c, Dog)    # c 是 Dog 類型
Out[8]: True



In [9]: isinstance(c, Animal)
Out[9]: True

 

 

c 不單單是 Dog, c 仍是 Animal, 由於 Animal 是 c的父類,所以 c 及時 Dog類型,也是 Animal 類型,可是反過來是不行的。code

In [12]: b = Animal()

In [13]: isinstance(b, Dog)
Out[13]: False

 

 

Dog 能夠當作 Animal,可是 Animal 不能夠當作 Dog對象

要理解多態,須要編寫一個 run_twice 函數。blog

class Animal:
    def run(self):
        print('Animal is running...')

class Dog(Animal):
    def run(self):
        print('dog is running...')

class Cat(Animal):
    def run(self):
        print('cat is running...')


def run_twice(animal):
    animal.run()
    animal.run()

dog = Dog()

run_twice(dog)

 

 

當咱們傳入 Animal 的實例時,run_twice() 就打印出:繼承

dog is running...
dog is running...

 

 

如今,若是咱們再定義一個Tortoise類型,也從Animal派生:class

class Animal:
    def run(self):
        print('Animal is running...')

class Dog(Animal):
    def run(self):
        print('dog is running...')

class Cat(Animal):
    def run(self):
        print('cat is running...')


class Tortoise(Animal):
    def run(self):
        print('tortoise is running...')


def run_twice(animal):
    animal.run()
    animal.run()

tortoise = Tortoise()

run_twice(tortoise)

 

 

當咱們調用 run_twice()時,傳入 Tortoise 的實例:變量

tortoise is running...
tortoise is running...

 

你會發現,新增一個Animal的子類,沒必要對run_twice()作任何修改,實際上,任何依賴Animal做爲參數的函數或者方法均可以不加修改地正常運行,緣由就在於多態。擴展

 

對於一個變量,咱們只須要知道它是Animal類型,無需確切地知道它的子類型,就能夠放心地調用run()方法,而具體調用的run()方法是做用在Animal、Dog、Cat仍是Tortoise對象上,由運行時該對象的確切類型決定,

這就是多態真正的威力:調用方只管調用,無論細節,而當咱們新增一種Animal的子類時,只要確保run()方法編寫正確,不用管原來的代碼是如何調用的。這就是著名的「開閉」原則:

  • 對擴展開放:容許新增Animal子類;
  • 對修改封閉:不須要修改依賴Animal類型的run_twice()等函數

 

靜態語言 vs 動態語言 

對於靜態語言(例如Java)來講,若是須要傳入Animal類型,則傳入的對象必須是Animal類型或者它的子類,不然,將沒法調用run()方法。
對於Python這樣的動態語言來講,則不必定須要傳入Animal類型。咱們只須要保證傳入的對象有一個run()方法就能夠了:

class Timer:
    def run(self):
        print('Start...')

def run_twice(animal):
    animal.run()
    animal.run()

timer = Timer()

run_twice(timer)

 

 

這就是動態語言的「鴨子類型」,它並不要求嚴格的繼承體系,一個對象只要「看起來像鴨子,走起路來像鴨子」,那麼就能夠被看作是鴨子。

 

小結 

動態語言的鴨子類型的特色決定了繼承不像靜態語言那樣是必須的。

相關文章
相關標籤/搜索