99re热视频这里只精品,久久久天堂国产精品女人,国产av一区二区三区,久久久精品成人免费看片,99久久精品免费看国产一区二区三区

類(4)

2018-02-24 15:48 更新

本節(jié)介紹類中一個非常重要的東西——繼承,其實也沒有那么重要,只是聽起來似乎有點讓初學者暈頭轉向,然后就感覺它屬于很高級的東西,真是情況如何?學了之后你自然有感受。

在現(xiàn)實生活中,“繼承”意味著一個人從另外一個人那里得到了一些什么,比如“繼承革命先烈的光榮傳統(tǒng)”、“某人繼承他老爹的萬貫家產”等??傊?,“繼承”之后,自己就在所繼承的方面省力氣、不用勞神費心,能輕松得到,比如繼承了萬貫家產,自己就一夜之間變成富豪。如果繼承了“革命先烈的光榮傳統(tǒng)”,自己是不是一下就變成革命者呢?

當然,生活中的繼承或許不那么嚴格,但是編程語言中的繼承是有明確規(guī)定和穩(wěn)定的預期結果的。

繼承(Inheritance)是面向對象軟 件技術當中的一個概念。如果一個類別A“繼承自”另一個類別B,就把這個A稱為“B的子類別”,而把B稱為“A的父類別”,也可以稱“B是A的超類”。

繼承可以使得子類別具有父類別的各種屬性和方法,而不需要再次編寫相同的代碼。在令子類別繼承父類別的同時,可以重新定義某些屬性,并重寫某些方法,即覆蓋父類別的原有屬性和方法,使其獲得與父類別不同的功能。另外,為子類別追加新的屬性和方法也是常見的做法。 (源自維基百科)

由上面對繼承的表述,可以簡單總結出繼承的意圖或者好處:

  • 可以實現(xiàn)代碼重用,但不是僅僅實現(xiàn)代碼重用,有時候根本就沒有重用
  • 實現(xiàn)屬性和方法繼承

誠然,以上也不是全部,隨著后續(xù)學習,對繼承的認識會更深刻。好友令狐蟲曾經這樣總結繼承:

從技術上說,OOP里,繼承最主要的用途是實現(xiàn)多態(tài)。對于多態(tài)而言,重要的是接口繼承性,屬性和行為是否存在繼承性,這是不一定的。事實上,大量工程實踐表明,重度的行為繼承會導致系統(tǒng)過度復雜和臃腫,反而會降低靈活性。因此現(xiàn)在比較提倡的是基于接口的輕度繼承理念。這種模型里因為父類(接口類)完全沒有代碼,因此根本談不上什么代碼復用了。

在Python里,因為存在Duck Type,接口定義的重要性大大的降低,繼承的作用也進一步的被削弱了。

另外,從邏輯上說,繼承的目的也不是為了復用代碼,而是為了理順關系。

他是大牛,或許讀者感覺比較高深,沒關系,隨著你的實踐經驗的積累,你也能對這個問題有自己獨到的見解。

或許你也要問我的觀點是什么?我的觀點就是:走著瞧!怎么理解?繼續(xù)向下看,只有你先深入這個問題,才能跳到更高層看這個問題。小馬過河的故事還記得吧?只有親自走入河水中,才知道河水的深淺。

對于python中的繼承,前面一直在使用,那就是我們寫的類都是新式類,所有新式類都是繼承自object類。不要忘記,新式類的一種寫法:

class NewStyle(object):
    pass

這就是典型的繼承。

基本概念

#!/usr/bin/env python
# coding=utf-8

__metaclass__ = type

class Person:
    def speak(self):
        print "I love you."

    def setHeight(self):
        print "The height is: 1.60m ."

    def breast(self, n):
        print "My breast is: ",n

class Girl(Person):
    def setHeight(self):
        print "The height is:1.70m ."

if __name__ == "__main__":
    cang = Girl()
    cang.setHeight()
    cang.speak()
    cang.breast(90)

上面這個程序,保存之后運行:

$ python 20901.py 
The height is:1.70m .
I love you.
My breast is:  90

對以上程序進行解釋,從中體會繼承的概念和方法。

首先定義了一個類Person,在這個類中定義了三個方法。注意,沒有定義初始化函數(shù),初始化函數(shù)在類中不是必不可少的。

然后又定義了一個類Girl,這個類的名字后面的括號中,是上一個類的名字,這就意味著Girl繼承了Person,Girl是Person的子類,Person是Girl的父類。

既然是繼承了Person,那么Girl就全部擁有了Person中的方法和屬性(上面的例子雖然沒有列出屬性)。但是,如果Girl里面有一個和Person同樣名稱的方法,那么就把Person中的同一個方法遮蓋住了,顯示的是Girl中的方法,這叫做方法的重寫

實例化類Girl之后,執(zhí)行實例方法cang.setHeight(),由于在類Girl中重寫了setHeight方法,那么Person中的那個方法就不顯作用了,在這個實例方法中執(zhí)行的是類Girl中的方法。

雖然在類Girl中沒有看到speak方法,但是因為它繼承了Person,所以cang.speak()就執(zhí)行類Person中的方法。同理cang.breast(90),它們就好像是在類Girl里面已經寫了這兩個方法一樣。既然繼承了,就是我的了。

多重繼承

所謂多重繼承,就是只某一個類的父類,不止一個,而是多個。比如:

#!/usr/bin/env python
# coding=utf-8

__metaclass__ = type

class Person:
    def eye(self):
        print "two eyes"

    def breast(self, n):
        print "The breast is: ",n

class Girl:
    age = 28
    def color(self):
        print "The girl is white"

class HotGirl(Person, Girl):
    pass

if __name__ == "__main__":
    kong = HotGirl()
    kong.eye()
    kong.breast(90)
    kong.color()
    print kong.age

在這個程序中,前面有兩個類:Person和Girl,然后第三個類HotGirl繼承了這兩個類,注意觀察繼承方法,就是在類的名字后面的括號中把所繼承的兩個類的名字寫上。但是第三個類中什么方法也沒有。

然后實例化類HotGirl,既然繼承了上面的兩個類,那么那兩個類的方法就都能夠拿過來使用。保存程序,運行一下看看

$ python 20902.py 
two eyes
The breast is:  90
The girl is white
28

值得注意的是,這次在類Girl中,有一個age = 28,在對HotGirl實例化之后,因為繼承的原因,這個類屬性也被繼承到HotGirl中,因此通過實例屬性kong.age一樣能夠得到該數(shù)據(jù)。

由上述兩個實例,已經清楚看到了繼承的特點,即將父類的方法和屬性全部承接到子類中;如果子類重寫了父類的方法,就使用子類的該方法,父類的被遮蓋。

多重繼承的順序

多重繼承的順序很必要了解。比如,如果一個子類繼承了兩個父類,并且兩個父類有同樣的方法或者屬性,那么在實例化子類后,調用那個方法或屬性,是屬于哪個父類的呢?造一個沒有實際意義,純粹為了解決這個問題的程序:

#!/usr/bin/env python
# coding=utf-8

class K1(object):
    def foo(self):
        print "K1-foo"

class K2(object):
    def foo(self):
        print "K2-foo"
    def bar(self):
        print "K2-bar"

class J1(K1, K2):
    pass

class J2(K1, K2):
    def bar(self):
        print "J2-bar"

class C(J1, J2):
    pass

if __name__ == "__main__":
    print C.__mro__
    m = C()
    m.foo()
    m.bar()

這段代碼,保存后運行:

$ python 20904.py 
(<class '__main__.C'>, <class '__main__.J1'>, <class '__main__.J2'>, <class '__main__.K1'>, <class '__main__.K2'>, <type 'object'>)
K1-foo
J2-bar

代碼中的print C.__mro__是要打印出類的繼承順序。從上面清晰看出來了。如果要執(zhí)行foo()方法,首先看J1,沒有,看J2,還沒有,看J1里面的K1,有了,即C==>J1==>J2==>K1;bar()也是按照這個順序,在J2中就找到了一個。

這種對繼承屬性和方法搜索的順序稱之為“廣度優(yōu)先”。

新式類用以及python3.x中都是按照此順序原則搜尋屬性和方法的。

但是,在舊式類中,是按照“深度優(yōu)先”的順序的。因為后面讀者也基本不用舊式類,所以不舉例。如果讀者愿意,可以自己模仿上面代碼,探索舊式類的“深度優(yōu)先”含義。

super函數(shù)

對于初始化函數(shù)的繼承,跟一般方法的繼承,還有點不同??梢钥聪旅娴睦樱?/p>

#!/usr/bin/env python
# coding=utf-8

__metaclass__ = type

class Person:
    def __init__(self):
        self.height = 160

    def about(self, name):
        print "{} is about {}".format(name, self.height)

class Girl(Person):
    def __init__(self):
        self.breast = 90

    def about(self, name):
        print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)

if __name__ == "__main__":
    cang = Girl()
    cang.about("canglaoshi")

在上面這段程序中,類Girl繼承了類Person。在類Girl中,初始化設置了self.breast = 90,由于繼承了Person,按照前面的經驗,Person的初始化函數(shù)中的self.height = 160也應該被Girl所繼承過來。然后在重寫的about方法中,就是用self.height。

實例化類Girl,并執(zhí)行cang.about("canglaoshi"),試圖打印出一句話canglaoshi is a hot girl, she is about 160, and her bereast is 90。保存程序,運行之:

$ python 20903.py 
Traceback (most recent call last):
  File "20903.py", line 22, in <module>
    cang.about("canglaoshi")
  File "20903.py", line 18, in about
    print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
AttributeError: 'Girl' object has no attribute 'height'

報錯!

程序員有一句名言:不求最好,但求報錯。報錯不是壞事,是我們長經驗的時候,是在告訴我們,那么做不對。

重要的是看報錯信息。就是我們要打印的那句話出問題了,報錯信息顯示self.height是不存在的。也就是說類Girl沒有從Person中繼承過來這個屬性。

原因是什么?仔細觀察類Girl,會發(fā)現(xiàn),除了剛才強調的about方法重寫了,__init__方法,也被重寫了。不要認為它的名字模樣奇怪,就不把它看做類中的方法(函數(shù)),它跟類Person中的__init__重名了,也同樣是重寫了那個初始化函數(shù)。

這就提出了一個問題。因為在子類中重寫了某個方法之后,父類中同樣的方法被遮蓋了。那么如何再把父類的該方法調出來使用呢?縱然被遮蓋了,應該還是存在的,不要浪費了呀。

python中有這樣一種方法,這種方式是被提倡的方法:super函數(shù)。

#!/usr/bin/env python
# coding=utf-8

__metaclass__ = type

class Person:
    def __init__(self):
        self.height = 160

    def about(self, name):
        print "{} is about {}".format(name, self.height)

class Girl(Person):
    def __init__(self):
        super(Girl, self).__init__()
        self.breast = 90

    def about(self, name):
        print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
        super(Girl, self).about(name)

if __name__ == "__main__":
    cang = Girl()
    cang.about("canglaoshi")

在子類中,__init__方法重寫了,為了調用父類同方法,使用super(Girl, self).__init__()的方式。super函數(shù)的參數(shù),第一個是當前子類的類名字,第二個是self,然后是點號,點號后面是所要調用的父類的方法。同樣在子類重寫的about方法中,也可以調用父類的about方法。

執(zhí)行結果:

$ python 20903.py 
canglaoshi is a hot girl, she is about 160, and her breast is 90
canglaoshi is about 160

最后要提醒注意:super函數(shù)僅僅適用于新式類。當然,你一定是使用的新式類?!跋残聟捙f”是程序員的嗜好。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號