什么是Python的多態(tài)?
多態(tài)的好處就是,當(dāng)我們需要傳入Dog、Cat、Tortoise……時(shí),我們只需要接收Animal類型就可以了,因?yàn)镈og、Cat、Tortoise……都是Animal類型,然后,按照Animal類型進(jìn)行操作即可。由于Animal類型有run()方法,因此,傳入的任意類型,只要是Animal類或者子類,就會(huì)自動(dòng)調(diào)用實(shí)際類型的run()方法,這就是多態(tài)的意思:
對(duì)于一個(gè)變量,我們只需要知道它是Animal類型,無需確切地知道它的子類型,就可以放心地調(diào)用run()方法,而具體調(diào)用的run()方法是作用在Animal、Dog、Cat還是Tortoise對(duì)象上,由運(yùn)行時(shí)該對(duì)象的確切類型決定,這就是多態(tài)真正的威力:調(diào)用方只管調(diào)用,不管細(xì)節(jié),而當(dāng)我們新增一種Animal的子類時(shí),只要確保run()方法編寫正確,不用管原來的代碼是如何調(diào)用的。這就是著名的“開閉”原則:
對(duì)擴(kuò)展開放:允許新增Animal子類;
對(duì)修改封閉:不需要修改依賴Animal類型的run_twice()等函數(shù)。
======================
多態(tài)即多種形態(tài),在運(yùn)行時(shí)確定其狀態(tài),在編譯階段無法確定其類型,這就是多態(tài)。Python中的多態(tài)和Java以及C++中的多態(tài)有點(diǎn)不同,Python中的變量是弱類型的,在定義時(shí)不用指明其類型,它會(huì)根據(jù)需要在運(yùn)行時(shí)確定變量的類型(個(gè)人覺得這也是多態(tài)的一種體現(xiàn)),并且Python本身是一種解釋性語言,不進(jìn)行預(yù)編譯,因此它就只在運(yùn)行時(shí)確定其狀態(tài),故也有人說Python是一種多態(tài)語言。在Python中很多地方都可以體現(xiàn)多態(tài)的特性,比如內(nèi)置函數(shù)len(object),len函數(shù)不僅可以計(jì)算字符串的長(zhǎng)度,還可以計(jì)算列表、元組等對(duì)象中的數(shù)據(jù)個(gè)數(shù),這里在運(yùn)行時(shí)通過參數(shù)類型確定其具體的計(jì)算過程,正是多態(tài)的一種體現(xiàn)。這有點(diǎn)類似于函數(shù)重載(一個(gè)編譯單元中有多個(gè)同名函數(shù),但參數(shù)不同),相當(dāng)于為每種類型都定義了一個(gè)len函數(shù)。這是典型的多態(tài)表現(xiàn)。有些朋友提出Python不支持多態(tài),我是完全不贊同的。 本質(zhì)上,多態(tài)意味著可以對(duì)不同的對(duì)象使用同樣的操作,但它們可能會(huì)以多種形態(tài)呈現(xiàn)出結(jié)果。len(object)函數(shù)就體現(xiàn)了這一點(diǎn)。在C++、Java、C#這種編譯型語言中,由于有編譯過程,因此就鮮明地分成了運(yùn)行時(shí)多態(tài)和編譯時(shí)多態(tài)。運(yùn)行時(shí)多態(tài)是指允許父類指針或名稱來引用子類對(duì)象,或?qū)ο蠓椒ǎ鴮?shí)際調(diào)用的方法為對(duì)象的類類型方法,這就是所謂的動(dòng)態(tài)綁定。編譯時(shí)多態(tài)有模板或范型、方法重載(overload)、方法重寫(override)等。而Python是動(dòng)態(tài)語言,動(dòng)態(tài)地確定類型信息恰恰體現(xiàn)了多態(tài)的特征。在Python中,任何不知道對(duì)象到底是什么類型,但又需要對(duì)象做點(diǎn)什么的時(shí)候,都會(huì)用到多態(tài)。
- 有一種稱為”鴨子類型(duck typing)“的東西,講的也是多態(tài):
_metaclass_=type # 確定使用新式類
class Duck:
def quack(self):
print "Quaaaaaack!"
def feathers(self):
print "The duck has white and gray feathers."
class Person:
def quack(self):
print "The person imitates a duck."
def feathers(self):
print "The person takes a feather from the ground and shows it."
def in_the_forest(duck):
duck.quack()
duck.feathers()
def game():
donald = Duck()
john = Person()
in_the_forest(donald)
in_the_forest(john)
game()
就in_the_forest函數(shù)而言,參數(shù)對(duì)象是一個(gè)鴨子類型,它實(shí)現(xiàn)了方法多態(tài)。但是實(shí)際上我們知道,從嚴(yán)格的抽象來講,Person類型和Duck完全風(fēng)馬牛不相及。
- 運(yùn)算符多態(tài)
def add(x,y):
return x+y
print add(1,2) #輸出3
print add("hello,","world") #輸出hello,world
print add(1,"abc") #拋出異常 TypeError: unsupported operand type(s) for +: 'int' and 'str'
Python的加法運(yùn)算符是”多態(tài)“的,理論上,我們實(shí)現(xiàn)的add方法支持任意支持加法的對(duì)象,但是我們不用關(guān)心兩個(gè)參數(shù)x和y具體是什么類型。
- Python同樣支持運(yùn)算符重載
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print v1 + v2
在C++, Java, C#中實(shí)現(xiàn)多態(tài)的方式通常有重寫和重載兩種,從上面兩段代碼,我們其實(shí)可以分析得出Python中實(shí)現(xiàn)多態(tài)也可以變相理解為重寫和重載。在Python中很多內(nèi)置函數(shù)和運(yùn)算符都是多態(tài)的。
[Reference]https://vancele.gitbooks.io/python/content/chapter7.html