從零開始的Python計劃#8.2 繼承

在討論繼承inheritance之前,我們要先討論關聯和聯繫

關聯和聯繫

關係是對象之間可能發生的事情,它們可以相互依賴,有三個層次的重要性:
聯繫——薄弱關係
聯繫是階級之間最薄弱的關係形式。 如果我們有兩個類,B完全獨立於A,但只需要a的一些屬性來運行它的方法。重要的是A和B可以彼此獨立。
聚集——中等關係
通常,如果類A需要類B來執行某些功能,則B對象將被創建並將其傳遞給A。存在一種循環,但是如果我們刪除對象A,那麼B的內容就可以在沒有對象的情況下生存。就是A要求B運行,B將在A中反饋,如果刪除A,B依然存在。
組成——牢固關係
類A由另一類B的一個或多個實例組成。換句話說,一個類是容器,另一個類是內容。(因此如果刪除A,則其內容對象B也將被刪除。沒有A就沒有B,因爲A包含B。)

聯繫實例

第一個例子:
Salary類是獨立的,它用init方法,取時長和付款率。將它們賦給屬性,然後會有年薪返回的方法(每月工作時間,自付工資*12)
在這裏插入圖片描述
employee也是獨立的,但在計算工資獎金時需要工資。當我們有annual_salary_with_bonus時,我們會通annual_salary年薪返回的是年薪加上自我獎金的總和。
在這裏插入圖片描述
因爲這裏沒有年薪,employee對象要傳入obj_sal。所以即使這兩個類是完全分開的,爲了計算Employee類的年薪和獎金annual_salary_with_bonus,我們需要傳遞obj_sal =Salary(40, 10.50)。
在這裏插入圖片描述
然後有一個對象employee,它是從類employees創建的。當我們想從obj_emp計算出帶獎金的年薪obj_emp.annual_salary_with_bonus,我們得傳遞作爲參數的obj_sal.get_annual_salary
我們需要在obj_sal運行accessor方法獲取值,並將其傳遞給employee。但我們不能在不知道annual_salary的情況下運行employee,這種關係就是聯繫,但關係很輕。


第二個實例:聚集
在這裏插入圖片描述
在這裏插入圖片描述
Salary類是獨立的,Employee需要Salary作爲其__init__參數的一部分存在。我們不需要傳遞Salary去運行Employee方法,但是需要Salary來運行Employee的init方法。
在這裏插入圖片描述
爲了讓我們能從類Employee中實例化一個對象,需要運行Employee和最後傳遞的屬性get_annual_salary。
沒有Salary,就不可能運行Employee。


第三個實例:組成
在這裏插入圖片描述
Salary不是獨立的,它是在Employee類內部創造的。
在Employee類中可以看到,創造了obj_salary是Salary(hrs,rate)。當我們如果刪除了對象Employee,Salary也會被刪除。
Employee需要存在Salary輸入參數,並需要在其__init__函數中創建Salary對象,Salary被Employee在內初始化,但Salary需要Employee的屬性hrs和rate作爲參數。
這是一段非常牢固的關係,當我們刪除Employee,Salary就會不存在。
在這裏插入圖片描述
這種牢固的關係顯然有一些缺點,當我們刪除一個類時,就不可能使用另一個類。

這些關係都很重要,因爲我們不只看一個獨立的實體,但是我們也要看到類之間是如何相互交織,互相依賴的。
當我們要用UML圖來描述這些類的話:

在這裏插入圖片描述

以上就是可以在類圖中使用的三個新規則:是我們在UML語言中用來描述它們流動的符號:
聯繫——A類傳遞給B類一些數據,B類用這些數據運行一個方法
集合——(可以看到有條線返回,並且有一個空的菱形)這表示在init方法中使用B的意思。
組成——(線尾有黑色菱形)刪除A,B也將不存在

繼承

在現實世界裏,許多對象是更通用對象的特定版本。(比如:舴艋和蜜蜂是一種特殊的昆蟲,除了一般的昆蟲特徵之外,它們有獨特的特點:舴艋會跳,蜜蜂有刺,會做蜂蜜和建造蜂巢。它們都是昆蟲,但是有各自特殊的屬性,我們可以通過使用對象之間的關係來指定這個特性關係。
當一個對象是另一個對象的專用版本時,就存在一種關係,這個特殊對象具有一般對象的所有特徵,再加上一些特殊的特徵。(比如,矩形是就是一個形狀,雛菊就是花,我們知道這是一種關係,需要去通用的類並生成一個特定的類。所有的特徵都是通用的,加上一些新的特徵。)

在面向對象編程OOP中,繼承是用於在類之間創建“is a”關係的概念。(什麼和什麼在類中是什麼關係)
面向對象編程中的繼承是基於超類和子類的概念的(舴艋是亞綱,昆蟲是超級綱,是特定的和通用的)
超類(基礎類):一般類
子類(派生類):專門類
超類的擴展版本繼承了超類的屬性和方法,可以添加新的屬性和方法
基本上就是把所有的東西都複製瞭然後添加新的東西。

繼承實例

舉個例子,我們需要創建一個小汽車類和皮卡車類
我們都知道這兩樣東西都是汽車,有品牌,年份型號和價格,因爲它們都有這個,所以這三個屬性可以是基(通用)類的屬性,超級類的基類的一般類。
但是汽車有很多門,皮卡有一個驅動類型。這些都是特定的類的一部分。

所以在UML圖中:
在圖中添加了很多特性,繼承是通過在子類和超類之間畫一條帶箭頭的線來表示的。
就像這個例子一樣:
在這裏插入圖片描述
Automobile類是普通類,所有的這些都適用於其他所有子類。Car類繼承了框中的所有內容,加上添加門,設置門,獲取門。所以Car類會有所有的東西。

Python中的繼承

在子類的類定義中表示繼承:
爲了表示繼承,將超類名稱放在括號裏,在子類名稱之後。所以對子類我們的格式是:class Sub_Class_Name(Super_Class_Name):
子類的初始化方法調用超類的初始化方法,然後初始化唯一數據屬性。(進入超級類,運行init方法,然後返回並運行init方法作爲子類的數據屬性)
添加唯一方法的方法定義,使子類成爲超級類的擴展。

Python中一個超級類的例子

在這裏插入圖片描述
有一個Vehicle類(超級類),init方法有make,model,price。我們可以setPrice設定價格,getPrice得到價格,str方法返回make,model和price的值。
在這裏插入圖片描述
進入另一個腳本,從vehicle導入剛纔的Vehicle類
創建一個名爲boat的子類來繼承Vehicle所做的一切,它有一個init方法,它接受從Vehicle類來的make,model和price。(我們可以看到Vehicle.__init )
用點符號.
init __調用Vehicle這個超類裏的所有東西。
self.__cabin_size = cabin,這是boat上特有的。然後接下去爲特定屬性創建兩個特定方法set_cabin_size和get_cabin_size。

在這裏插入圖片描述
我們也可以在另一個腳本中導入相同的腳本並對car執行相同的操作,方法大致和以上相同。
所以以上Vehicle就是超級類,boat和car就是它的子類。

測試繼承

在這裏插入圖片描述
先從vehicle導入Vehicle類
運行main
創造一個car1的對象,具有Car子類。(把Mazda作爲一個品牌,2010年,4500是價格,4是門的數量),boat1對象同理。
當我們打印時,會繼承超類的字符串,就會得到打印所有普通類的字符串:
在這裏插入圖片描述
並且還能打印子類中的具體方法。

類變量和實例變量

類變量:
—在類內部但在任何方法外部聲明;
—也稱爲靜態變量
—可以在不創建類實例的情況下訪問
—由類的所有實例共享

實例變量:
—在self關鍵字處理的方法中聲明(意味着它們只針對那個實例)
—該類的每個實例可以爲實例變量具有唯一的值(每個對象中的self.variable在實例之間可以有不同的值)

示例:

在這裏插入圖片描述
我們可以看到開頭有Ball類,裏面有很多我們之前看到過的內容,但是從未在之前文章中出現過單獨放一個變量的(color=“Red”)。這個就是一個類變量,意味着這個類的所有實例將分享它。但是init,get_color,get_size對實例來說是個體可變化的。
運行main函數,會發現打印的顏色都是一樣的,因爲color是個類變量,所以每個實例都將共享。
然而size大小是獨立的,我們在前面用self.聲明瞭它,所以3會被正確地儲存在ball1中,5也被正確存儲在ball2中。
在這裏插入圖片描述

我們可以看到底下在Ball上調用color並把顏色改成了Blue(Ball.color=“Blue”),**不創建類的實例就可以訪問類變量。**給color類變量分配了一個新的字符串值,之後運行相同的代碼就會發現,兩個實例的color值都被變成了Blue。
size大小保持不變,因爲size是這個類的即時變量,不在實例之間共享。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章