在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ exercise44.繼承 Vs.包含
附錄 A-練習(xí) 9:生成一個(gè)空文件(Touch, New-Item)
附錄 A-練習(xí) 10:復(fù)制文件 (cp)
exercise44.繼承 Vs.包含
附錄 A-練習(xí) 14:刪除文件 (rm)
附錄 A-練習(xí) 11:移動(dòng)文件 (mv)
exercise46.項(xiàng)目骨架
附錄 A-練習(xí) 3:如果你迷路了
exercise37.復(fù)習(xí)符號(hào)
exercise47.自動(dòng)化測(cè)試
exercise3.數(shù)字和數(shù)學(xué)計(jì)算
附錄 A-練習(xí) 1:安裝
exercise32.循環(huán)和列表
exercise31.做出決定
exercise42.對(duì)象、類、以及從屬關(guān)系
exercise48.更復(fù)雜的用戶輸入
下一步
簡(jiǎn)介
附錄 A-練習(xí) 7:刪除路徑 (rmdir)
exercise49.寫代碼語(yǔ)句
exercise18.命名, 變量, 代碼, 函數(shù)
exercise12.提示別人
exercise14.提示和傳遞
exercise40.模塊, 類和對(duì)象
附錄 A-練習(xí) 12:查看文件 (less, MORE)
exercise9.打印, 打印, 打印
exercise13.參數(shù), 解包, 變量
exercise30. Else 和 If
exercise28. 布爾表達(dá)式
附錄 A-練習(xí) 4:創(chuàng)建一個(gè)路徑 (mkdir)
附錄 A-練習(xí) 15:退出命令行 (exit)
exercise25. 更多更多的練習(xí)
exercise6.字符串和文本
exercise2.注釋和井號(hào)“#”
exercise21. 函數(shù)的返回值
附錄 A-下一步
exercise1.第一個(gè)程序
exercise23. 閱讀代碼
附錄 A-練習(xí) 5:改變當(dāng)前路徑 (cd)
exercise17.更多文件操作
exercise24. 更多的練習(xí)
exercise19.函數(shù)和變量
exercise51.從瀏覽器獲取輸入
exercise22. 到目前為止你學(xué)到了什么?
exercise41.學(xué)會(huì)說(shuō)面向?qū)ο?/span>
exercise52.開始你的 web 游戲
exercise20. 函數(shù)和文件
exercise15.讀文件
exercise45.你來(lái)制作一個(gè)游戲
exercise10.那是什么?
exercise8.打印, 打印
exercise35.分支和函數(shù)
exercise26. 恭喜你,可以進(jìn)行一次考試了
exercise33.while 循環(huán)
exercise29. IF 語(yǔ)句
exercise36.設(shè)計(jì)和調(diào)試
exercise0.安裝和準(zhǔn)備
exercise50.你的第一個(gè)網(wǎng)站
附錄 A-練習(xí) 2:路徑, 文件夾, 名錄 (pwd)
exercise38.列表操作
附錄 A-練習(xí) 6:列出當(dāng)前路徑 (ls)
exercise16.讀寫文件
exercise4.變量和命名
exercise34.訪問(wèn)列表元素
exercise11.提問(wèn)
exercise43.基本的面向?qū)ο蟮姆治龊驮O(shè)計(jì)
附錄 A-簡(jiǎn)介
附錄 A-練習(xí) 8:目錄切換(pushd, popd)
來(lái)自老程序員的建議
exercise27. 記住邏輯
exercise5.更多的變量和打印
exercise7.更多的打?。ㄝ敵觯?/span>
附錄 A-練習(xí) 13:輸出文件 (cat)
exercise39.字典,可愛的字典

exercise44.繼承 Vs.包含

在有關(guān)英雄戰(zhàn)勝邪惡的童話中,總是有某種形式的黑暗森林。它可能是一個(gè)山洞,森林,另一個(gè)星球或者其他地方,每個(gè)人都知道英雄不應(yīng)該去。當(dāng)然,當(dāng)不就之后壞人被你找到的時(shí)候,你發(fā)現(xiàn),英雄已經(jīng)去那個(gè)愚蠢的森林里殺壞人去了??雌饋?lái)英雄進(jìn)入了一種狀態(tài),這種狀態(tài)要求英雄必須在這個(gè)邪惡的森林中冒險(xiǎn)。

在面向?qū)ο缶幊讨?,繼承就是那個(gè)黑暗森林。有經(jīng)驗(yàn)的程序員知道要避免這種邪惡,因?yàn)樗麄冎?黑暗森林深處有著多重繼承這個(gè)邪惡的皇后。 她喜歡那她那龐大的牙齒吃掉軟件和程序員。但這個(gè)森林是如此強(qiáng)大,如此誘人,幾乎每一個(gè)程序員都必須進(jìn)入它,與邪惡的皇后戰(zhàn)斗,盡量做到全身而退,才可以稱自己是真正的程序員。你不能抗拒的繼承森林的誘惑,所以你進(jìn)去了。冒險(xiǎn)之后,你試著遠(yuǎn)離那個(gè)邪惡的森林,當(dāng)你再次被迫進(jìn)入的時(shí)候,你會(huì)攜帶一支軍隊(duì)進(jìn)入(這段翻譯的太爛了,實(shí)在沒(méi)辦法把編程和童話聯(lián)系起來(lái)?。?/p>

這是一種有趣的方式來(lái)解說(shuō)我要在這節(jié)練習(xí)教你的東西,它叫做繼承,當(dāng)你使用它的時(shí)候,一定要當(dāng)心再當(dāng)心。正在森林里和女王戰(zhàn)斗的程序員可能告訴你你必須進(jìn)去。他們這么說(shuō)是因?yàn)樗麄冃枰愕膸兔?,可能因?yàn)樗麄儎?chuàng)建了太多他們已經(jīng)無(wú)法掌控的東西。但是你一定要記得:

大多數(shù)繼承的用途,可以簡(jiǎn)化或用組合物所取代,并應(yīng)不惜一切代價(jià)避免多重繼承。

什么是繼承

繼承是用來(lái)描述一個(gè)類從它的父類那里獲得大部分甚至全部父類的功能。當(dāng)你寫下 class Foo(Bar)的時(shí)候,就發(fā)生了繼承,這句代碼的意思是“創(chuàng)建一個(gè)叫做 Foo 的類,并繼承 Bar” 。當(dāng)你執(zhí)行這句的時(shí)候,編程語(yǔ)言使得 Foo 的實(shí)例所有的行為都跟 Bar 的實(shí)例一樣。這么做,可以讓你在類 Bar 中放一些通用功能,而那些需要特殊定制的函數(shù)或功能可以放在類 Foo 中。

當(dāng)你需要做這些特殊化函數(shù)編寫的時(shí)候,父子類之間有 3 中交互方法:

1.子類的方法隱性繼承父類方法 2.子類重寫父類的方法 3.對(duì)子類的操作改變父類

我將按順序給你展示這 3 種交互方式,并給你看它們的代碼。

隱性繼承

首先,我將給你展示的是隱性繼承發(fā)生在你在父類中定義了方法,而在子類中沒(méi)有:

class Parent(object):

    def implicit(self):
        print "PARENT implicit()"

class Child(Parent):
    pass

dad = Parent()
son = Child()

dad.implicit()
son.implicit()

在 class Child 下使用 pass 的目的是告訴 Python,在這里你想要一個(gè)空白的塊。這里創(chuàng)建了一個(gè)叫做 Child 的類,但是沒(méi)有在這個(gè)類中定義任何性的方法。它將從類 Parent 繼承獲得所有的方法。當(dāng)你執(zhí)行這段代碼的時(shí)候,你會(huì)看到:

$ python ex44a.py
PARENT implicit()
PARENT implicit()

注意一下,盡管我再代碼的 13 行調(diào)用了 son.implicit(),而類 Child 并沒(méi)有一個(gè)定義叫做 implicit 的方法,代碼仍然正常工作了,因?yàn)樗{(diào)用了 Parent 中定義的同名方法。這個(gè)高速你的是:如果你在基類(i.e., Parent)中定義了一個(gè)方法,那么所有的子類(i.e., Child) 都可以自動(dòng)的獲得這個(gè)功能。對(duì)于你需要在很多類中有重復(fù)的方法來(lái)說(shuō),非常方便。

重寫方法

關(guān)于有些方法是隱式調(diào)用的問(wèn)題原因在于有時(shí)候你想讓子類有不同的表現(xiàn)。這時(shí)你想重寫子類中的方法且有效的覆蓋父類中的方法。要做到這一點(diǎn),你只需要在子類中定義一個(gè)同名的方法就行,例如

class Parent(object):

    def override(self):
        print "PARENT override()"

class Child(Parent):

    def override(self):
        print "CHILD override()"

dad = Parent()
son = Child()

dad.override()
son.override()

在這個(gè)例子中,兩個(gè)類中我都有一個(gè)叫做 override 的方法,所以讓我們來(lái)看看當(dāng)你運(yùn)行此例時(shí)都發(fā)生了什么

$ python ex44b.py
PARENT override()
CHILD override()

你可以看到,當(dāng)?shù)?14 行執(zhí)行時(shí),它執(zhí)行了父類的 override 方法,因?yàn)樽兞?dad 是一個(gè)父類實(shí)例,但是當(dāng)?shù)?15 行執(zhí)行時(shí),打印的是子類的 override 方法,這是因?yàn)?son 是一個(gè)子類的實(shí)例,這個(gè)子類重寫了那個(gè)方法,定義了自己的版本。

休息以下,在繼續(xù)下面的內(nèi)容之前,嘗試練習(xí)這兩種方法。

之前或之后改變父類

第三種使用繼承的方式比較特別,你想在父類版本的方法執(zhí)行行為前后給出些提示,你首先像上個(gè)例子那樣重寫了方法,接著你使用一個(gè) Python 內(nèi)建的叫做 super 的方法得到了父類版本的方法調(diào)用。以下這個(gè)例子就是這么做的,你可以感受一下上面的描述是什么意思。

class Parent(object):

    def altered(self):
        print "PARENT altered()"

class Child(Parent):

    def altered(self):
        print "CHILD, BEFORE PARENT altered()"
        super(Child, self).altered()
        print "CHILD, AFTER PARENT altered()"

dad = Parent()
son = Child()

dad.altered()
son.altered()

重要的地方在于 9-11 行,在 son.altered()被調(diào)用前我做了如下操作:

1.因?yàn)槲乙呀?jīng)重寫了子類的 Child.altered 方法,第 9 行的運(yùn)行結(jié)果應(yīng)該和你的期待是一樣 2.在這個(gè)例子中,我打算使用 super 來(lái)得到父類的 Parent.altered 版本。 3.在第 10 行,我調(diào)用了 super(Child, self).altered()方法, 這個(gè)方法能夠意識(shí)到繼承的發(fā)生,并給你獲得類 Parent。你可以這樣讀這行代碼“調(diào)用 super,參數(shù)為 Child 和 self,然后不管它返回什么,調(diào)用方法 altered ” 4.在這種情況下,父類的 Parent.altered 版本執(zhí)行,并打印出父類的信息。 5.最后,代碼從 Parent.altered 返回, Child.altered 方法繼續(xù)打印出剩下的信息。

運(yùn)行了程序之后,你應(yīng)該能看到下面的內(nèi)容:

$ python ex44c.py
PARENT altered()
CHILD, BEFORE PARENT altered()
PARENT altered()
CHILD, AFTER PARENT altered()

三種組合使用

為了論證上面的三種方式,我有一個(gè)最終版本的文件,該文件給你展示了每一種繼承方式的交互:

class Parent(object):

    def override(self):
        print "PARENT override()"

    def implicit(self):
        print "PARENT implicit()"

    def altered(self):
        print "PARENT altered()"

class Child(Parent):

    def override(self):
        print "CHILD override()"

    def altered(self):
        print "CHILD, BEFORE PARENT altered()"
        super(Child, self).altered()
        print "CHILD, AFTER PARENT altered()"

dad = Parent()
son = Child()

dad.implicit()
son.implicit()

dad.override()
son.override()

dad.altered()
son.altered()

通讀每一行代碼,不管有沒(méi)有被重寫,寫一個(gè)注釋用來(lái)解釋每一行實(shí)現(xiàn)了什么,然后將代碼運(yùn)行起來(lái),確認(rèn)你的結(jié)果和你的期望是否一致:

$ python ex44d.py
PARENT implicit()
PARENT implicit()
PARENT override()
CHILD override()
PARENT altered()
CHILD, BEFORE PARENT altered()
PARENT altered()
CHILD, AFTER PARENT altered()

使用 super()的原因

這看起來(lái)應(yīng)該是常識(shí),但是隨后我們即將進(jìn)入一個(gè)叫做所多重繼承的麻煩事。 多重繼承是指當(dāng)你定義一個(gè)的類的時(shí)候,從一個(gè)或多個(gè)類繼承,例如:

class SuperFun(Child, BadStuff):
    pass

上述代碼的意思是, "創(chuàng)建一個(gè)叫做 SuperFun 的類,它同時(shí)繼承類 Child 和類 BadStuff ."

在這個(gè)例子中,只要你隱式的調(diào)用任何 SuperFun 的實(shí)例,Python 把必須從類 Child 和 BadStuff 查詢可能的函數(shù),但是,查找也需要一個(gè)順序。為了做到這點(diǎn),Python 使用"方法解析順序"(MRO)和一種叫做 C3 的運(yùn)算法則來(lái)直接獲得。

因?yàn)?MRO 是復(fù)雜的,并使用了明確定義的算法,Python 不能讓你來(lái)獲得正確的 MRO,相反的,Python 提供給你 super()方法,它用來(lái)處理所有這一切你需要改變類型的行為,如同我在 Child.altered 所實(shí)現(xiàn)的。使用 super()你不必?fù)?dān)心得到的是否是正確的方法,Python 會(huì)幫你找到正確的那個(gè)。

init中使用 super()

super()最常見的用途是在基類的init方法里。這通常是你需要在子類里實(shí)現(xiàn)什么事情,然后完成父類初始化的地方。以下是在類 Child 中這樣做的一個(gè)簡(jiǎn)單的例子:

class Child(Parent):

    def __init__(self, stuff):
        self.stuff = stuff
        super(Child, self).__init__()

除了我在init中初始化父類之前定義了一些變量,這個(gè)跟上面的例子 Child.altered 幾乎是一樣的。

包含

繼承是有用的, 但另一種方式僅僅是用其他類和模塊就做到了同樣的事情, 而沒(méi)有使用隱性繼承。如果你看一下使用繼承的三種方式,其中的兩種方法涉及編寫新的代碼來(lái)替換或改變父類功能。這可以很容易地通過(guò)調(diào)用模塊函數(shù)復(fù)制。下面是一個(gè)例子:

class Other(object):

    def override(self):
        print "OTHER override()"

    def implicit(self):
        print "OTHER implicit()"

    def altered(self):
        print "OTHER altered()"

class Child(object):

    def __init__(self):
        self.other = Other()

    def implicit(self):
        self.other.implicit()

    def override(self):
        print "CHILD override()"

    def altered(self):
        print "CHILD, BEFORE OTHER altered()"
        self.other.altered()
        print "CHILD, AFTER OTHER altered()"

son = Child()

son.implicit()
son.override()
son.altered()

在這段代碼中,我沒(méi)有使用名字 Parent,因?yàn)闆](méi)有父子的 is-a 關(guān)系了。這是一個(gè) has-a 關(guān)系,在這個(gè)關(guān)系中 Child has-a Other 被用來(lái)保證代碼的正常工作。當(dāng)我運(yùn)行代碼時(shí),看到以下輸出:

$ python ex44e.py
OTHER implicit()
CHILD override()
CHILD, BEFORE OTHER altered()
OTHER altered()
CHILD, AFTER OTHER altered()

你可以看到 Child 和 Other 中的大部分代碼實(shí)現(xiàn)了相同的功能。唯一的不同之處在于我必須定義一個(gè) Child.implicit 方法去做一個(gè)動(dòng)作. 然后我可以問(wèn)問(wèn)自己,如果我需要一個(gè) Other 類,是不是只要把它放在一個(gè)叫做 other.py 的模塊中就可以?

什么時(shí)候用繼承,什么時(shí)候用包含

繼承與包含的問(wèn)題可以歸結(jié)為試圖解決可重復(fù)使用代碼的問(wèn)題。你不想在你的軟件中有重復(fù)的代碼,因?yàn)檫@不是高效的干凈的代碼。繼承通過(guò)創(chuàng)建一種機(jī)制,讓你在基類中有隱含的功能來(lái)解決這個(gè)問(wèn)題。而包含則是通過(guò)給你的模塊和函數(shù)可以在其他類別被調(diào)用來(lái)解決這個(gè)問(wèn)題。

如果這兩種方案都能解決代碼復(fù)用問(wèn)題的話,哪一個(gè)更合適呢?答案是主觀的,這看起來(lái)是令人難以相信的,但是我會(huì)給你 3 個(gè)指導(dǎo)性原則:

1.不惜一切代價(jià)避免多重繼承,因?yàn)樗珡?fù)雜太不可靠。如果你必須要使用它,那么一定要知道類的層次結(jié)構(gòu),并花時(shí)間找到每一個(gè)類是從哪里來(lái)的。 2.將代碼封裝為模塊,這樣就可以在許多不同的地方或情況使用。 3.只有當(dāng)有明顯相關(guān)的可重用的代碼,且在一個(gè)共同概念下時(shí),可以使用繼承。

不要變成規(guī)則的奴隸。關(guān)于面向?qū)ο缶幊桃涀〉氖牵哼@是一個(gè)程序員創(chuàng)建打包和共享代碼的社會(huì)習(xí)俗。因?yàn)樗且粋€(gè)社會(huì)習(xí)俗,但在 Python 的法典中,你可能會(huì)因?yàn)楦愫献鞯娜硕黄缺荛_這些規(guī)則。在這種情況下,了解他們是如何使用規(guī)則的,然后去適應(yīng)形勢(shì)。

附加題

這節(jié)練習(xí)中只有一個(gè)附加題,因?yàn)檫@其實(shí)是一個(gè)很大的練習(xí)。閱讀 http://www.python.org/dev/peps/pep-0008/ 并嘗試將它應(yīng)用到你的代碼中。你會(huì)發(fā)現(xiàn),有些內(nèi)容跟你從這本書學(xué)到的不同,但是現(xiàn)在你應(yīng)該能夠理解他們的建議,并將其應(yīng)用到自己的代碼中。本書中剩余部分的代碼可能會(huì)也可能不會(huì)遵循這些準(zhǔn)則,這個(gè)要取決于這些準(zhǔn)則是否會(huì)使代碼更加混亂。我建議你也這樣做,因?yàn)槔斫獗茸尨蠹叶紝?duì)你深?yuàn)W的知識(shí)有印象更重要。

常見問(wèn)題

Q: 我如何更好的解決我以前沒(méi)有遇到的問(wèn)題?

更好的解決問(wèn)題的辦法只有一個(gè),那就是盡量多的自己解決遇到的問(wèn)題。通常,人們遇到一個(gè)棘手的問(wèn)題,就會(huì)沖出去尋找答案。當(dāng)你必須要把事情做好的時(shí)候,這種方法很好,但是如果你有時(shí)間的話,最好還是自己想辦法解決這個(gè)問(wèn)題。盡你所能的思考這個(gè)問(wèn)題,嘗試一切可能的辦法,直到你解決這個(gè)問(wèn)題。在此之后你找到的答案,你覺得會(huì)更加令人滿意,而且你還會(huì)得到更好的解決問(wèn)題的方法。

Q: 對(duì)象不是復(fù)制的類嗎?

在某些語(yǔ)言里(比如 JavaScript) 是這樣的。這些被稱為原型的語(yǔ)言,這些語(yǔ)言中對(duì)象和類沒(méi)有什么不同之處。然而在 Python 中,類作為模板,可以生成新對(duì)象,類似于如何使用模具制造硬幣。