關於類,看官想必已經有了感受,看下面的代碼,請仔細閱讀,並看看是否可以發現點什麼問題呢?python
#!/usr/bin/env python #coding:utf-8 class Person: def __init__(self, name, lang, email): self.name = name self.lang = lang self.email = email def author(self): return self.name class Programmer: def __init__(self, name, lang, email, system, website): self.name = name self.lang = lang self.email = email self.system = system self.website = website def pythoner(self): pythoner_list = [ self.name, self.lang, self.email, self.system, self.website ] return pythoner_list if __name__=="__main__": writer = Person("qiwsir","Chinese","qiwsir@gmail.com") python = Programmer("qiwsir","Python","qiwsir@gmail.com","Ubutun","qiwsir.github.io") print "My name is:%s"%writer.author() print "I write program by:%s"%python.pythoner()[1]
上面這段代碼,運行起來沒有什麼問題,可是,仔細看,發現有兩個類,一個名字叫作Person,另一個叫作Programmer,這還不是問題所在,問題所在是這兩個類的構造函數中,存在這相同的地方:self.name=name,self.lang=lang,self.email=email,這對於追求代碼質量的程序員,通常是不容許的。最好不要有重複代碼或者冗餘代碼。但是,在兩個類中都要有這些參數,應該怎麼辦呢?git
看下面的代碼,裏面有兩個類A,B。這段程序可以正確運行,每一個類的功能是僅僅打印指定的內容。程序員
#!/usr/bin/env python #coding:utf-8 class A: def __init__(self): print "aaa" class B: def __init__(self): print "bbb" if __name__=="__main__": a = A() b = B() #運行結果 aaa bbb
上面的兩個類彼此之間沒有所謂的父子關係。如今稍加改變,將類B改寫,注意觀察與上面的差別。github
#!/usr/bin/env python #coding:utf-8 class A: def __init__(self): print "aaa" class B(A): #這裏和上面程序不一樣。B繼承了A def __init__(self): print "bbb" if __name__=="__main__": a = A() b = B() #運行結果 aaa bbb
這段程序中,類B跟前面的那段有一點不一樣,class B(A):,這樣寫就代表了B相對A的關係:B是A的子類,B從A繼承A的全部東西(子承父業)。web
可是,看官發現了沒有,運行結果同樣。是的,那是覺得在B中儘管繼承了A,可是沒有調用任何A的東西,就比如兒子從老爸那裏繼承了財富,可是兒子一個子也沒動,外界看到的和沒有繼承同樣。編程
#!/usr/bin/env python #coding:utf-8 class A: def __init__(self): print "aaa" class B(A): def __init__(self): #print "bbb" A.__init__(self) #運行繼承的父類 if __name__=="__main__": a = A() b = B() #運行結果 aaa aaa
這回運行結果有了變化,原本b=B()是運行類B,可是B繼承了A,而且在初始化的構造函數中,引入A的構造函數,因此,就運行A的結果相應結果了。函數
下面把最開頭的那端程序用子類繼承的方式重寫,能夠是這樣的:code
#!/usr/bin/env python #coding:utf-8 class Person: def __init__(self, name, lang, email): self.name = name self.lang = lang self.email = email def author(self): return self.name """ class Programmer: def __init__(self, name, lang, email, system, website): self.name = name self.lang = lang self.email = email self.system = system self.website = website def pythoner(self): pythoner_list = [ self.name, self.lang, self.email, self.system, self.website ] return pythoner_list """ class Programmer(Person): #繼承父類Person def __init__(self, name, lang, email, system, website): Person.__init__(self,name,lang,email) #將Person.__init__()的功能繼承到這裏 #self.name = name #這三句是Person中已經搞定的,就不用重複 #self.lang = lang #經過繼承已經實現了這三句的功能 #self.email = email self.system = system #子類中不一樣於Person父類部分 self.website = website def pythoner(self): pythoner_list = [ self.name, self.lang, self.email, self.system, self.website ] return pythoner_list if __name__=="__main__": writer = Person("qiwsir","Chinese","qiwsir@gmail.com") python = Programmer("qiwsir","Python","qiwsir@gmail.com","Ubutun","qiwsir.github.io") print "My name is:%s"%writer.author() print "I write program by:%s"%python.pythoner()[1]
代碼運行結果與前面同樣。繼承
列位是否理解了子類和父類、繼承的特色。若是你有一個老爹,是一個高官或者富豪,那麼你就官二代或者富二代了,你就從他們那裏繼承了不少財富,因此生活就不用太勞累了。這就是繼承的做用。在代碼中,也相似,繼承可以讓寫代碼的少勞累一些。接口
對於爲何要用繼承,好友@令狐蟲 大俠給了以很是精彩的解釋:
從技術上說,OOP裏,繼承最主要的用途是實現多 態。對於多態而言,重要的是接口繼承性,屬性和行爲是否存在繼承性,這是不必定的。事實上,大量工程實踐代表,重度的行爲繼承會致使系統過分複雜和臃腫, 反而會下降靈活性。所以如今比較提倡的是基於接口的輕度繼承理念。這種模型裏由於父類(接口類)徹底沒有代碼,所以根本談不上什麼代碼複用了。
在Python裏,由於存在Duck Type,接口定義的重要性大大的下降,繼承的做用也進一步的被削弱了。
另外,從邏輯上說,繼承的目的也不是爲了複用代碼,而是爲了理順關係。
我表示徹底贊同上述解釋。不過看官若是不理解,也沒有關係,上述解釋中的精神,的確須要在編程實踐中感悟才能領會到的。