- Django 2.0 入門與實踐
- 李健
- 1993字
- 2020-06-30 17:19:14
7.3 類繼承
繼承是代碼重用的好辦法,Python中的繼承就像現實生活中的繼承一樣,子類可以什么都不做就擁有了父類的屬性或方法。
7.3.1 單繼承
單繼承就是一個子類只有一個基類的繼承方式,語法是:class子類名(基類名): …。
還是以汽車為例來講解單繼承。汽車不是只有燃油的傳統小汽車,還有特斯拉這種電動車,雖然它們都是汽車,都有品牌、顏色等屬性,但是在一些細節上還是有區別的。據此可以定義一個Car基類,它包含所有汽車的通用屬性,然后再定義一個OilCar類和ECar類分別代表燃油汽車和電動車:

接下來分別實例化OilCar和ECar類,看看它們是不是真的能夠使用基類的屬性與方法:

由此可見,對象o是OilCar類型,同時也是Car的一個實例。子類不但可以直接使用父類的屬性(brand、color)與方法(print_car),而且還可以增加新方法(power)。
7.3.2 多繼承
多繼承就是一個子類可以繼承多個父類的繼承方式,相對于單繼承來說,多繼承更復雜也更難以控制,容易造成菱形繼承問題,即兩個父類同時繼承了一個基類,而子類會包含多個父類的內容,產生代碼歧義,因此很多編程語言都摒棄了這種繼承方式如Java和C#。Python是允許多繼承的,這對于開發人員來說即提供了更多的代碼編寫方案,同時也引入了更多的潛在問題,因此開發人員應時刻注意多繼承的風險。
雖然編者并不建議開發人員使用多繼承的方式編寫代碼,但是仍在這里對多繼承做一個簡單介紹,多繼承的語法與單繼承類似:class子類名(基類1,基類2…): …。下面是一個非常簡單的多繼承的例子:

類C同時繼承了類A和類B,那么它應該同時擁有類A和類B的屬性與方法,執行以下代碼進行查看:
>>> c = C() >>> c.run(5) 我在以5米/秒的速度跑步 >>> c.speak("你好") 我在說: 你好
上面的代碼非常簡單,因為類A和類B既沒有構造函數也沒有重復的屬性和方法,那么如果它們都有構造函數并且有同名的方法時會發生什么呢?

執行以下代碼:
>>> c = C(18) >>> c.intro() 我叫 18 >>> c.run(5) 我在以5米/秒的速度跑步 >>> c.speak("你好") 我在說: 你好
從上面的執行結果來看,本來我想介紹我的年齡,但是卻輸出了“我叫18”,而另外兩個方法還能正常執行。這種現象是繼承順序導致的,類A在類B的前面,所以對于同名的屬性與方法子類都會調用類A的。
上面是普通方法在多繼承中的表現,對于構造方法來說就更復雜了。Python中類的構造方法基本按照以下方式執行。
如果子類有自己的構造方法,那么在實例化子類的時候就會執行子類的構造方法,不會執行基類的構造方法,例如:

如果子類沒有構造方法,在單繼承中則會直接調用基類的構造方法,例如:

如果子類有多個基類并且子類沒有自己的構造函數,則會按順序查找父類,找到第一個有構造函數的基類并執行,例如:

7.3.3 方法重載
有時雖然父類已經提供了一些方法,但是這些方法可能不能滿足子類的需求,所以可以在子類中對父類方法進行重寫。
還是以單繼承為例,前面的例子中子類OilCar和ECar都直接使用了父類的print_car()方法,接下來希望在print_car()函數的輸出中還能展示當前車輛的動力類型,此時就需要重寫父類的print_car()方法,具體修改如下:

重新調用print_car()方法查看執行結果:
>>> o = OilCar("奔馳", "紅色") >>> o.print_car() 品牌: 奔馳 , 顏色: 紅色 , 動力:汽油 >>> e = ECar("特斯拉", "黑色") >>> e.print_car() 品牌: 特斯拉 , 顏色: 黑色 , 動力:電池
執行正常,子類已經重寫了父類方法,而且不同的子類之間沒有干擾。
7.3.4 super函數
仔細觀察上面方法重載的例子可以發現,兩個子類中print_car()非常相似,只有很少的一部分代碼有區別,本著代碼重用原則,可以使用super函數在子類中調用父類方法,以達到減少子類代碼冗余的目的。
Super是Python的內置函數,可以用來調用父類的方法,這在方法被重載時非常有用。Super函數的語法:super([type[,object-or-type]])。
Super函數有兩種用法:①在單繼承結構中,super可以隱式地返回父類。②支持多繼承,這也是除Python外幾乎目前所有編程語言中唯一一種能做到合理使用多繼承的方式,super使得開發人員可以很好地解決菱形繼承問題。不管哪種用法,super的調用都類似下面形式:
class C(B): def method(self, arg): super().method(arg) #等同于: super(C, self).method(arg)
注意
super這種不傳參數的用法只能用在類方法中,Python解釋器會自動填充參數。
第二個參數object-or-type一般都是self。
了解了以上知識后,使用super修改上面代碼:

7.3.5 訪問權限
前面例子中所有類的屬性與方法都是公有的,也就是說,子類可以沒有限制地使用基類的任何成員。但是有時還需要對類成員的訪問權限加以控制,如只允許類內部使用,或者只允許類本身和子類使用。
□ 類的私有屬性如下。
__private_attrs:以兩個下畫線開頭,不能在類的外部使用,在類內部使用時:self.__ private_attrs。
□ 類的私有方法:
__private_methods:以兩個下畫線開頭,不能在類的外部使用,在類內部使用時:self.__private_methods。
讀者可通過下面的例子看看私有屬性與公有屬性的區別:

訪問公有變量與私有變量:

可見在類外部是不能訪問私有變量的,但是其實Python的私有變量是一個偽私有變量,使用dir函數(dir是Python的內置函數,可以用來查看對象的所有屬性與方法)查看實例at:

從輸出結果可見,at包含了一個屬性_AccessTest__private,這個屬性其實就是我們前面定義的__private屬性,這是Python的名稱修飾(name mangling)功能對__private的重命名。我們繼續訪問這個_AccessTest__private屬性,看看它是不是真的等于__private呢?
>>> print(at._AccessTest__private) 1
果然符合預期。
- Vue.js 3.x快速入門
- ExtGWT Rich Internet Application Cookbook
- Advanced Machine Learning with Python
- CockroachDB權威指南
- Power Up Your PowToon Studio Project
- Web交互界面設計與制作(微課版)
- Building a Recommendation Engine with Scala
- 零基礎學Python網絡爬蟲案例實戰全流程詳解(入門與提高篇)
- Flutter跨平臺開發入門與實戰
- Python項目實戰從入門到精通
- QGIS Python Programming Cookbook(Second Edition)
- Python Data Science Cookbook
- Kubernetes進階實戰
- Java Web開發基礎與案例教程
- JBoss AS 7 Development