Python面向對象編程指南


抽象是隱藏多余細節的藝術。在面向對象的概念中,抽象的直接表現形式通常為類。雖然Python是解釋性語言,但是它是面向對象的,從設計之初就已經是一門面向對象的語言。Python基本上提供了面向對象編程語言的所有元素,如果你已經至少掌握了一門面向對象語言,那么利用Python進行面向對象程序設計將會相當容易。下面就來了解一下如何在Python中進行對象編程。


一. 如何定義一個類


  在進行python面向對象編程之前,先來了解幾個術語:類,類對象,實例對象,屬性,函數和方法。

  類是對現實世界中一些事物的封裝,定義一個類可以采用下面的方式來定義:

 

[python] view plain copy
 
  1. class className:  
  2.     block  
  注意類名后面有個冒號,在block塊里面就可以定義屬性和方法了。當一個類定義完之后,就產生了一個類對象。類對象支持兩種操作:引用和實例化。引用操作是通過類對象去調用類中的屬性或者方法,而實例化是產生出一個類對象的實例,稱作實例對象。比如定義了一個people類:
[python] view plain copy
 
  1. class people:  
  2.     name = 'jack'       #定義了一個屬性  
  3.     #定義了一個方法  
  4.     def printName(self):  
  5.         print self.name  

 

  people類定義完成之后就產生了一個全局的類對象,可以通過類對象來訪問類中的屬性和方法了。當通過people.name(至於為什么可以直接這樣訪問屬性后面再解釋,這里只要理解類對象這個概念就行了)來訪問時,people.name中的people稱為類對象,這點和C++中的有所不同。當然還可以進行實例化操作,p=people( ),這樣就產生了一個people的實例對象,此時也可以通過實例對象p來訪問屬性或者方法了(p.name).

  理解了類、類對象和實例對象的區別之后,我們來了解一下Python中屬性、方法和函數的區別。

  在上面代碼中注釋的很清楚了,name是一個屬性,printName( )是一個方法,與某個對象進行綁定的函數稱作為方法。一般在類里面定義的函數與類對象或者實例對象綁定了,所以稱作為方法;而在類外定義的函數一般沒有同對象進行綁定,就稱為函數。


二. 屬性


  在類中我們可以定義一些屬性,比如:

[python] view plain copy
 
  1. class people:  
  2.     name = 'jack'  
  3.     age = 12  
  4.   
  5. p = people()  
  6. print p.name,p.age  
  定義了一個people類,里面定義了name和age屬性,默認值分別為'jack'和12。在定義了類之后,就可以用來產生實例化對象了,這句p = people( )實例化了一個對象p,然后就可以通過p來讀取屬性了。這里的name和age都是公有的,可以直接在類外通過對象名訪問,如果想定義成私有的,則需在前面加2個下划線 ' __'。
[python] view plain copy
 
  1. class people:  
  2.     __name = 'jack'  
  3.     __age = 12  
  4.   
  5. p = people()  
  6. print p.__name,p.__age  
  這段程序運行會報錯:
[plain] view plain copy
 
  1. Traceback (most recent call last):  
  2.   File "C:/PycharmProjects/FirstProject/oop.py", line 6, in <module>  
  3.     print p.__name,p.__age  
  4. AttributeError: people instance has no attribute '__name  

  提示找不到該屬性,因為私有屬性是不能夠在類外通過對象名來進行訪問的。在Python中沒有像C++中public和private這些關鍵字來區別公有屬性和私有屬性,它是以屬性命名方式來區分,如果在屬性名前面加了2個下划線'__',則表明該屬性是私有屬性,否則為公有屬性(方法也是一樣,方法名前面加了2個下划線的話表示該方法是私有的,否則為公有的)。


三. 方法


  在類中可以根據需要定義一些方法,定義方法采用def關鍵字,在類中定義的方法至少會有一個參數,,一般以名為'self'的變量作為該參數(用其他名稱也可以),而且需要作為第一個參數。下面看個例子:

[python] view plain copy
 
  1. class people:  
  2.     __name = 'jack'  
  3.     __age = 12  
  4.   
  5.     def getName(self):  
  6.         return self.__name  
  7.     def getAge(self):  
  8.         return self.__age  
  9.   
  10. p = people()  
  11. print p.getName(),p.getAge()  

  如果對self不好理解的話,可以把它當做C++中類里面的this指針一樣理解,就是對象自身的意思,在用某個對象調用該方法時,就將該對象作為第一個參數傳遞給self。


四. 類中內置的方法


  在Python中有一些內置的方法,這些方法命名都有比較特殊的地方(其方法名以2個下划線開始然后以2個下划線結束)。類中最常用的就是構造方法和析構方法。

  構造方法__init__(self,....):在生成對象時調用,可以用來進行一些初始化操作,不需要顯示去調用,系統會默認去執行。構造方法支持重載,如果用戶自己沒有重新定義構造方法,系統就自動執行默認的構造方法。

  析構方法__del__(self):在釋放對象時調用,支持重載,可以在里面進行一些釋放資源的操作,不需要顯示調用。

  還有其他的一些內置方法,比如 __cmp__( ), __len( )__等。下面是常用的內置方法:

 

 內置方法  說明
 __init__(self,...)  初始化對象,在創建新對象時調用
 __del__(self)  釋放對象,在對象被刪除之前調用
 __new__(cls,*args,**kwd)  實例的生成操作
 __str__(self)  在使用print語句時被調用
 __getitem__(self,key)  獲取序列的索引key對應的值,等價於seq[key]
 __len__(self)  在調用內聯函數len()時被調用
 __cmp__(stc,dst)  比較兩個對象src和dst
 __getattr__(s,name)  獲取屬性的值
 __setattr__(s,name,value)  設置屬性的值
 __delattr__(s,name)  刪除name屬性
 __getattribute__()  __getattribute__()功能與__getattr__()類似
 __gt__(self,other)  判斷self對象是否大於other對象
 __lt__(slef,other)  判斷self對象是否小於other對象
 __ge__(slef,other)  判斷self對象是否大於或者等於other對象
 __le__(slef,other)  判斷self對象是否小於或者等於other對象
 __eq__(slef,other)  判斷self對象是否等於other對象
 __call__(self,*args)  把實例對象作為函數調用
  __init__():__init__方法在類的一個對象被建立時,馬上運行。這個方法可以用來對你的對象做一些你希望的初始化。注意,這個名稱的開始和結尾都是雙下划線。代碼例子:

 

[python] view plain copy
 
  1. # Filename: class_init.py  
  2. class Person:  
  3.     def __init__(self, name):  
  4.         self.name = name  
  5.     def sayHi(self):  
  6.         print 'Hello, my name is', self.name  
  7.   
  8. p = Person('Swaroop')  
  9. p.sayHi()  
  10.   
  11. 輸出:  
  12. Hello, my name is Swaroop  
  __new__():__new__()在__init__()之前被調用,用於生成實例對象。利用這個方法和類屬性的特性可以實現設計模式中的單例模式。單例模式是指創建唯一對象嗎,單例模式設計的類只能實例化一個對象。
[python] view plain copy
 
  1. # -*- coding: UTF-8 -*-  
  2.   
  3. class Singleton(object):  
  4.     __instance = None                       # 定義實例  
  5.   
  6.     def __init__(self):  
  7.         pass  
  8.   
  9.     def __new__(cls, *args, **kwd):         # 在__init__之前調用  
  10.         if Singleton.__instance is None:    # 生成唯一實例  
  11.             Singleton.__instance = object.__new__(cls, *args, **kwd)  
  12.         return Singleton.__instance  
  __getattr__()、__setattr__()和__getattribute__():當讀取對象的某個屬性時,python會自動調用__getattr__()方法。例如,fruit.color將轉換為fruit.__getattr__(color)。當使用賦值語句對屬性進行設置時,python會自動調用__setattr__()方法。__getattribute__()的功能與__getattr__()類似,用於獲取屬性的值。但是__getattribute__()能提供更好的控制,代碼更健壯。注意,python中並不存在__setattribute__()方法。代碼例子:

 

[python] view plain copy
 
  1. # -*- coding: UTF-8 -*-  
  2.   
  3. class Fruit(object):  
  4.     def __init__(self, color="red", price=0):  
  5.         self.__color = color  
  6.         self.__price = price  
  7.   
  8.     def __getattribute__(self, item):              # <span style="font-family:宋體;font-size:12px;">獲取屬性的方法</span>  
  9.         return object.__getattribute__(self, item)  
  10.   
  11.     def __setattr__(self, key, value):  
  12.         self.__dict__[key] = value  
  13.   
  14. if __name__ == "__main__":  
  15.     fruit = Fruit("blue", 10)  
  16.     print fruit.__dict__.get("_Fruit__color")    # <span style="font-family:宋體;font-size:12px;">獲取color屬性</span>  
  17.     fruit.__dict__["_Fruit__price"] = 5  
  18.     print fruit.__dict__.get("_Fruit__price")    # <span style="font-family:宋體;font-size:12px;">獲取price屬性</span>  

  Python不允許實例化的類訪問私有數據,但你可以使用object._className__attrName訪問這些私有屬性。

  __getitem__():如果類把某個屬性定義為序列,可以使用__getitem__()輸出序列屬性中的某個元素.假設水果店中銷售多鍾水果,可以通過__getitem__()方法獲取水果店中的沒種水果。代碼例子:

 

 

[python] view plain copy
 
  1. # -*- coding: UTF-8 -*-  
  2.   
  3. class FruitShop:  
  4.      def __getitem__(self, i):      # 獲取水果店的水果  
  5.          return self.fruits[i]        
  6.   
  7. if __name__ == "__main__":  
  8.     shop = FruitShop()  
  9.     shop.fruits = ["apple", "banana"]  
  10.     print shop[1]  
  11.     for item in shop:               # 輸出水果店的水果  
  12.         print item,  
  輸出:

 

 

[plain] view plain copy
 
  1. banana  
  2. apple banana  
  _ _str__():__str__()用於表示對象代表的含義,返回一個字符串.實現了__str__()方法后,可以直接使用print語句輸出對象,也可以通過函數str()觸發__str__()的執行。這樣就把對象和字符串關聯起來,便於某些程序的實現,可以用這個字符串來表示某個類。代碼例子:
[python] view plain copy
 
  1. # -*- coding: UTF-8 -*-  
  2.   
  3. class Fruit:       
  4.     '''''Fruit類'''               #為Fruit類定義了文檔字符串  
  5.     def __str__(self):          # 定義對象的字符串表示  
  6.         return self.__doc__  
  7.   
  8. if __name__ == "__main__":  
  9.     fruit = Fruit()  
  10.     print str(fruit)            # 調用內置函數str()觸發__str__()方法,輸出結果為:Fruit類  
  11.     print fruit                 #直接輸出對象fruit,返回__str__()方法的值,輸出結果為:Fruit類  
   __call__():在類中實現__call__()方法,可以在對象創建時直接返回__call__()的內容。使用該方法可以模擬靜態方法。代碼例子:
[python] view plain copy
 
  1. # -*- coding: UTF-8 -*-  
  2.   
  3. class Fruit:  
  4.     class Growth:        # 內部類  
  5.         def __call__(self):  
  6.             print "grow ..."  
  7.   
  8.     grow = Growth()      # 調用Growth(),此時將類Growth作為函數返回,即為外部類Fruit定義方法grow(),grow()將執行__call__()內的代碼  
  9. if __name__ == '__main__':  
  10.     fruit = Fruit()  
  11.     fruit.grow()         # 輸出結果:grow ...  
  12.     Fruit.grow()         # 輸出結果:grow ...  

 


五. 類屬性、實例屬性、類方法、實例方法以及靜態方法


  在了解了類基本的東西之后,下面看一下python中這幾個概念的區別。

  先來談一下類屬性和實例屬性

  在前面的例子中我們接觸到的就是類屬性,顧名思義,類屬性就是類對象所擁有的屬性,它被所有類對象的實例對象所共有,在內存中只存在一個副本,這個和C++中類的靜態成員變量有點類似。對於公有的類屬性,在類外可以通過類對象和實例對象訪問。

[python] view plain copy
 
  1. class people:  
  2.     name = 'jack'  #公有的類屬性  
  3.     __age = 12     #私有的類屬性  
  4.   
  5. p = people()  
  6.   
  7. print p.name             #正確  
  8. print people.name        #正確  
  9. print p.__age            #錯誤,不能在類外通過實例對象訪問私有的類屬性  
  10. print people.__age       #錯誤,不能在類外通過類對象訪問私有的類屬性  
   實例屬性是不需要在類中顯示定義的,比如:

 

[python] view plain copy
 
  1. class people:  
  2.     name = 'jack'  
  3.   
  4. p = people()  
  5. p.age =12  
  6. print p.name    #正確  
  7. print p.age     #正確  
  8.   
  9. print people.name    #正確  
  10. print people.age     #錯誤  
  在類外對類對象people進行實例化之后,產生了一個實例對象p,然后p.age = 12這句給p添加了一個實例屬性age,賦值為12。這個實例屬性是實例對象p所特有的,注意,類對象people並不擁有它(所以不能通過類對象來訪問這個age屬性)。當然還可以在實例化對象的時候給age賦值。

 

 

[python] view plain copy
 
  1. class people:  
  2.     name = 'jack'  
  3.       
  4.     #__init__()是內置的構造方法,在實例化對象時自動調用  
  5.     def __init__(self,age):  
  6.         self.age = age  
  7.   
  8. p = people(12)  
  9. print p.name    #正確  
  10. print p.age     #正確  
  11.   
  12. print people.name    #正確  
  13. print people.age     #錯誤  
   如果需要在類外修改類屬性,必須通過類對象去引用然后進行修改。如果通過實例對象去引用,會產生一個同名的實例屬性,這種方式修改的是實例屬性,不會影響到類屬性,並且之后如果通過實例對象去引用該名稱的屬性,實例屬性會強制屏蔽掉類屬性,即引用的是實例屬性,除非刪除了該實例屬性。
[python] view plain copy
 
  1. class people:  
  2.     country = 'china'  
  3.       
  4.   
  5. print people.country  
  6. p = people()  
  7. print p.country  
  8. p.country = 'japan'   
  9. print p.country      #實例屬性會屏蔽掉同名的類屬性  
  10. print people.country  
  11. del p.country    #刪除實例屬性  
  12. print p.country  

 

  下面來看一下類方法、實例方法和靜態方法的區別。

  類方法:是類對象所擁有的方法,需要用修飾器"@classmethod"來標識其為類方法,對於類方法,第一個參數必須是類對象,一般以"cls"作為第一個參數(當然可以用其他名稱的變量作為其第一個參數,但是大部分人都習慣以'cls'作為第一個參數的名字,就最好用'cls'了),能夠通過實例對象和類對象去訪問。

[python] view plain copy
 
  1. class people:  
  2.     country = 'china'  
  3.       
  4.     #類方法,用classmethod來進行修飾  
  5.     @classmethod  
  6.     def getCountry(cls):  
  7.         return cls.country  
  8.   
  9. p = people()  
  10. print p.getCountry()    #可以用過實例對象引用  
  11. print people.getCountry()    #可以通過類對象引用  

  類方法還有一個用途就是可以對類屬性進行修改:

 

[python] view plain copy
 
  1. class people:  
  2.     country = 'china'  
  3.       
  4.     #類方法,用classmethod來進行修飾  
  5.     @classmethod  
  6.     def getCountry(cls):  
  7.         return cls.country  
  8.          
  9.     @classmethod  
  10.     def setCountry(cls,country):  
  11.         cls.country = country  
  12.           
  13.   
  14. p = people()  
  15. print p.getCountry()    #可以用過實例對象引用  
  16. print people.getCountry()    #可以通過類對象引用  
  17.   
  18. p.setCountry('japan')     
  19.   
  20. print p.getCountry()     
  21. print people.getCountry()  

 

  運行結果:

 

[plain] view plain copy
 
  1. china  
  2. china  
  3. japan  
  4. japan  

 

  結果顯示在用類方法對類屬性修改之后,通過類對象和實例對象訪問都發生了改變。

  實例方法:在類中最常定義的成員方法,它至少有一個參數並且必須以實例對象作為其第一個參數,一般以名為'self'的變量作為第一個參數(當然可以以其他名稱的變量作為第一個參數)。在類外實例方法只能通過實例對象去調用,不能通過其他方式去調用。

[python] view plain copy
 
  1. class people:  
  2.     country = 'china'  
  3.       
  4.     #實例方法  
  5.     def getCountry(self):  
  6.         return self.country  
  7.           
  8.   
  9. p = people()  
  10. print p.getCountry()         #正確,可以用過實例對象引用  
  11. print people.getCountry()    #錯誤,不能通過類對象引用實例方法  
   靜態方法:需要通過修飾器"@staticmethod"來進行修飾,靜態方法不需要多定義參數。
[python] view plain copy
 
  1. class people:  
  2.     country = 'china'  
  3.      
  4.     @staticmethod  
  5.     #靜態方法  
  6.     def getCountry():  
  7.         return people.country  
  8.           
  9.   
  10. print people.getCountry()  

  對於類屬性和實例屬性,如果在類方法中引用某個屬性,該屬性必定是類屬性,而如果在實例方法中引用某個屬性(不作更改),並且存在同名的類屬性,此時若實例對象有該名稱的實例屬性,則實例屬性會屏蔽類屬性,即引用的是實例屬性,若實例對象沒有該名稱的實例屬性,則引用的是類屬性;如果在實例方法更改某個屬性,並且存在同名的類屬性,此時若實例對象有該名稱的實例屬性,則修改的是實例屬性,若實例對象沒有該名稱的實例屬性,則會創建一個同名稱的實例屬性。想要修改類屬性,如果在類外,可以通過類對象修改,如果在類里面,只有在類方法中進行修改。

  從類方法和實例方法以及靜態方法的定義形式就可以看出來,類方法的第一個參數是類對象cls,那么通過cls引用的必定是類對象的屬性和方法;而實例方法的第一個參數是實例對象self,那么通過self引用的可能是類屬性、也有可能是實例屬性(這個需要具體分析),不過在存在相同名稱的類屬性和實例屬性的情況下,實例屬性優先級更高。靜態方法中不需要額外定義參數,因此在靜態方法中引用類屬性的話,必須通過類對象來引用。


六. 繼承和多重繼承


  上面談到了類的基本定義和使用方法,這只體現了面向對象編程的三大特點之一:封裝。下面就來了解一下另外兩大特征:繼承和多態。

  在Python中,如果需要的話,可以讓一個類去繼承一個類,被繼承的類稱為父類或者超類、也可以稱作基類,繼承的類稱為子類。並且Python支持多繼承,能夠讓一個子類有多個父類。

  Python中類的繼承定義基本形式如下:

[python] view plain copy
 
  1. #父類  
  2. class superClassName:  
  3.     block  
  4.   
  5. #子類  
  6. class subClassName(superClassName):  
  7.     block  
  在定義一個類的時候,可以在類名后面緊跟一對括號,在括號中指定所繼承的父類,如果有多個父類,多個父類名之間用逗號隔開。以大學里的學生和老師舉例,可以定義一個父類UniversityMember,然后類Student和類Teacher分別繼承類UniversityMember:
[python] view plain copy
 
  1. # -*- coding: UTF-8 -*-  
  2.   
  3. class UniversityMember:  
  4.   
  5.     def __init__(self,name,age):  
  6.         self.name = name  
  7.         self.age = age  
  8.   
  9.     def getName(self):  
  10.         return self.name  
  11.   
  12.     def getAge(self):  
  13.         return self.age  
  14.   
  15. class Student(UniversityMember):  
  16.   
  17.     def __init__(self,name,age,sno,mark):  
  18.         UniversityMember.__init__(self,name,age)     #注意要顯示調用父類構造方法,並傳遞參數self  
  19.         self.sno = sno  
  20.         self.mark = mark  
  21.   
  22.     def getSno(self):  
  23.         return self.sno  
  24.   
  25.     def getMark(self):  
  26.         return self.mark  
  27.   
  28.   
  29.   
  30. class Teacher(UniversityMember):  
  31.   
  32.     def __init__(self,name,age,tno,salary):  
  33.         UniversityMember.__init__(self,name,age)  
  34.         self.tno = tno  
  35.         self.salary = salary  
  36.   
  37.     def getTno(self):  
  38.         return self.tno  
  39.   
  40.     def getSalary(self):  
  41.         return self.salary  

  在大學中的每個成員都有姓名和年齡,而學生有學號和分數這2個屬性,老師有教工號和工資這2個屬性,從上面的代碼中可以看到:

  1)在Python中,如果父類和子類都重新定義了構造方法__init( )__,在進行子類實例化的時候,子類的構造方法不會自動調用父類的構造方法,必須在子類中顯示調用。

  2)如果需要在子類中調用父類的方法,需要以”父類名.方法“這種方式調用,以這種方式調用的時候,注意要傳遞self參數過去。

  對於繼承關系,子類繼承了父類所有的公有屬性和方法,可以在子類中通過父類名來調用,而對於私有的屬性和方法,子類是不進行繼承的,因此在子類中是無法通過父類名來訪問的。

  Python支持多重繼承。對於多重繼承,比如

  class SubClass(SuperClass1,SuperClass2)

  此時有一個問題就是如果SubClass沒有重新定義構造方法,它會自動調用哪個父類的構造方法?這里記住一點:以第一個父類為中心。如果SubClass重新定義了構造方法,需要顯示去調用父類的構造方法,此時調用哪個父類的構造方法由你自己決定;若SubClass沒有重新定義構造方法,則只會執行第一個父類的構造方法。並且若SuperClass1和SuperClass2中有同名的方法,通過子類的實例化對象去調用該方法時調用的是第一個父類中的方法。


七. 多態


  多態即多種形態,在運行時確定其狀態,在編譯階段無法確定其類型,這就是多態。Python中的多態和Java以及C++中的多態有點不同,Python中的變量是弱類型的,在定義時不用指明其類型,它會根據需要在運行時確定變量的類型(個人覺得這也是多態的一種體現),並且Python本身是一種解釋性語言,不進行預編譯,因此它就只在運行時確定其狀態,故也有人說Python是一種多態語言。在Python中很多地方都可以體現多態的特性,比如內置函數len(object),len函數不僅可以計算字符串的長度,還可以計算列表、元組等對象中的數據個數,這里在運行時通過參數類型確定其具體的計算過程,正是多態的一種體現。這有點類似於函數重載(一個編譯單元中有多個同名函數,但參數不同),相當於為每種類型都定義了一個len函數。這是典型的多態表現。有些朋友提出Python不支持多態,我是完全不贊同的。

  本質上,多態意味着可以對不同的對象使用同樣的操作,但它們可能會以多種形態呈現出結果。len(object)函數就體現了這一點。在C++、Java、C#這種編譯型語言中,由於有編譯過程,因此就鮮明地分成了運行時多態和編譯時多態。運行時多態是指允許父類指針或名稱來引用子類對象,或對象方法,而實際調用的方法為對象的類類型方法,這就是所謂的動態綁定。編譯時多態有模板或范型、方法重載(overload)、方法重寫(override)等。而Python是動態語言,動態地確定類型信息恰恰體現了多態的特征。在Python中,任何不知道對象到底是什么類型,但又需要對象做點什么的時候,都會用到多態。

  能夠直接說明多態的兩段示例代碼如下:
   1、方法多態
[python] view plain copy
 
  1. # -*- coding: UTF-8 -*-  
  2.   
  3. _metaclass_=type # 確定使用新式類  
  4. class calculator:  
  5.     
  6.     def count(self,args):  
  7.         return 1  
  8.   
  9. calc=calculator() #自定義類型  
  10.   
  11. from random import choice  
  12. obj=choice(['hello,world',[1,2,3],calc]) #obj是隨機返回的 類型不確定  
  13. print type(obj)  
  14. print obj.count('a') #方法多態  

  對於一個臨時對象obj,它通過Python的隨機函數取出來,不知道具體類型(是字符串、元組還是自定義類型),都可以調用count方法進行計算,至於count由誰(哪種類型)去做怎么去實現我們並不關心。

  有一種稱為”鴨子類型(duck typing)“的東西,講的也是多態:

[python] view plain copy
 
  1. _metaclass_=type # 確定使用新式類  
  2. class Duck:  
  3.     def quack(self):   
  4.         print "Quaaaaaack!"  
  5.     def feathers(self):   
  6.         print "The duck has white and gray feathers."  
  7.    
  8. class Person:  
  9.     def quack(self):  
  10.         print "The person imitates a duck."  
  11.     def feathers(self):   
  12.         print "The person takes a feather from the ground and shows it."  
  13.    
  14. def in_the_forest(duck):  
  15.     duck.quack()  
  16.     duck.feathers()  
  17.    
  18. def game():  
  19.     donald = Duck()  
  20.     john = Person()  
  21.     in_the_forest(donald)  
  22.     in_the_forest(john)  
  23.    
  24. game()  
  就in_the_forest函數而言,參數對象是一個鴨子類型,它實現了方法多態。但是實際上我們知道,從嚴格的抽象來講,Person類型和Duck完全風馬牛不相及。
   2、運算符多態

 

[python] view plain copy
 
  1. def add(x,y):  
  2.     return x+y  
  3.   
  4. print add(1,2) #輸出3  
  5.   
  6. print add("hello,","world") #輸出hello,world  
  7.   
  8. print add(1,"abc") #拋出異常 TypeError: unsupported operand type(s) for +: 'int' and 'str'  
  上例中,顯而易見,Python的加法運算符是”多態“的,理論上,我們實現的add方法支持任意支持加法的對象,但是我們不用關心兩個參數x和y具體是什么類型。
  Python同樣支持運算符重載,實例如下:

 

 

[python] view plain copy
 
  1. class Vector:  
  2.    def __init__(self, a, b):  
  3.       self.a = a  
  4.       self.b = b  
  5.   
  6.    def __str__(self):  
  7.       return 'Vector (%d, %d)' % (self.a, self.b)  
  8.      
  9.    def __add__(self,other):  
  10.       return Vector(self.a + other.a, self.b + other.b)  
  11.   
  12. v1 = Vector(2,10)  
  13. v2 = Vector(5,-2)  
  14. print v1 + v2  
  一兩個示例代碼當然不能從根本上說明多態。 普遍認為面向對象最有價值最被低估的特征其實是多態。我們所理解的多態的實現和子類的虛函數地址綁定有關系,多態的效果其實和函數地址運行時動態綁定有關。在C++, Java, C#中實現多態的方式通常有重寫和重載兩種,從上面兩段代碼,我們其實可以分析得出Python中實現多態也可以變相理解為重寫和重載。在Python中很多內置函數和運算符都是多態的。

 

參考文獻:

http://www.cnblogs.com/dolphin0520/archive/2013/03/29/2986924.html

http://www.cnblogs.com/jeffwongishandsome/archive/2012/10/06/2713258.html

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM