一、類的組合 1、什麼是組合 組合:描述的是類與類之間的關係,是一種什麼有什麼關係 一個類產生的對象,該對象擁有一個屬性,這個屬性的值是來自於另外一個類的對象 2、什麼是繼承(回顧一下) 繼承:描述的是類與類之間,什麼是什麼的關係 3、組合的作用 解決代碼冗餘 來看一個實例子: 總結: 組合與繼承都 ...
一、類的組合
1、什麼是組合
組合:描述的是類與類之間的關係,是一種什麼有什麼關係
一個類產生的對象,該對象擁有一個屬性,這個屬性的值是來自於另外一個類的對象
2、什麼是繼承(回顧一下)
繼承:描述的是類與類之間,什麼是什麼的關係
3、組合的作用
解決代碼冗餘
來看一個實例子:
class Equip: #武器裝備類 def fire(self): print('release Fire skill') class Riven: #英雄Riven的類,一個英雄需要有裝備,因而需要組合Equip類 camp='Noxus' def __init__(self,nickname): self.nickname=nickname self.equip=Equip() #用Equip類產生一個裝備,賦值給實例的equip屬性 r1=Riven('銳雯雯') r1.equip.fire() #可以使用組合的類產生的對象所持有的方法 release Fire skill
總結:
組合與繼承都是有效地利用已有類的資源的重要方式。但是二者的概念和使用場景皆不同,怎麼選擇還是看我們自己
1、繼承的方式
通過繼承建立了派生類與基類之間的關係,它是一種'是'的關係,比如白馬是馬,人是動物。
當類之間有很多相同的功能,提取這些共同的功能做成基類,用繼承比較好,比如老師是人,學生是人
2、組合的方式
用組合的方式建立了類與組合的類之間的關係,它是一種‘有’的關係,比如教授有生日,教授教python和linux課程,教授有學生s1、s2、s3...
當類之間有顯著不同,並且較小的類是較大的類所需要的組件時,用組合比較好
二、類的封裝
1、什麼是封裝
封裝就是把一堆屬性存起來,封的概念就把這些屬性給隱藏起來
強調:封裝單從字面意思去看等同於隱藏,但其實封裝絕對不是單純意義的隱藏
2、封裝的目的
1 、封裝數據屬性的目的:把數據屬性封裝起來,然後需要開闢介面給類外部的使用者使用,好處是
我們可以在介面之上添加控制邏輯,從而嚴格空間訪問者對屬性的操作
2、 封裝函數屬性的目的:為了隔離複雜度
封裝的終極奧義:明確地區分內外,對外是隱藏的,對內是開放的
3、如何用封裝
如何把屬性隱藏起來,就在屬性前面加上__(雙下劃線)開頭(註意不要加__結尾)
註意:
1、其實這種隱藏只是一種語法上的變形,對外不對內
為一個屬性名加__開頭(註意不要加__結尾),會在類定義階段將屬性名統一變形:_自己的類名__屬性名
2、這種語法意義上變形,只在類定義階段發生一次,類定義之後,新增的__開頭的屬性都沒有變形的效果
3、如果父類不想讓子類覆蓋自己的方法,可以在方法名前加__開頭
#其實這僅僅這是一種變形操作且僅僅只在類定義階段發生變形 #類中所有雙下劃線開頭的名稱如__x都會在類定義時自動變形成:_類名__x的形式: class A: __N=0 #類的數據屬性就應該是共用的,但是語法上是可以把類的數據屬性設置成私有的如__N,會變形為_A__N def __init__(self): self.__X=10 #變形為self._A__X def __foo(self): #變形為_A__foo print('from A') def bar(self): self.__foo() #只有在類內部才可以通過__foo的形式訪問到. #A._A__N是可以訪問到的, #這種,在外部是無法通過__x這個名字訪問到。
4、 封裝不是單純意義的隱藏
封裝的真諦在於明確地區分內外,封裝的屬性可以直接在內部使用,而不能被外部直接使用,然而定義屬性的目的終歸是要用,外部要想用類隱藏的屬性,需要我們為其開闢介面,讓外部能夠間接地用到我們隱藏起來的屬性,那這麼做的意義何在???
1、封裝數據:將數據隱藏起來這不是目的。隱藏起來然後對外提供操作該數據的介面,然後我們可以在介面附加上對該數據操作的限制,以此完成對數據屬性操作的嚴格控制。
class Teacher: def __init__(self,name,age): # self.__name=name # self.__age=age self.set_info(name,age) def tell_info(self): print('姓名:%s,年齡:%s' %(self.__name,self.__age)) def set_info(self,name,age): if not isinstance(name,str): raise TypeError('姓名必須是字元串類型') if not isinstance(age,int): raise TypeError('年齡必須是整型') self.__name=name self.__age=age t=Teacher('duoduo',18) #沒封裝前,對象可以隨意的改變屬性 t.tell_info() #封裝後,只能操作設計者讓你操作的地方 t.set_info('qianduoduo',19) t.tell_info()
2、封裝方法:目的是隔離複雜度
封裝方法舉例:
1. 你的身體沒有一處不體現著封裝的概念:你的身體把膀胱尿道等等這些尿的功能隱藏了起來,然後為你提供一個尿的介面就可以了(介面就是你的。。。,),你總不能把膀胱掛在身體外面,上廁所的時候就跟別人炫耀:hi,man,你瞅我的膀胱,看看我是怎麼尿的。
2. 電視機本身是一個黑盒子,隱藏了所有細節,但是一定會對外提供了一堆按鈕,這些按鈕也正是介面的概念,所以說,封裝並不是單純意義的隱藏!!!
提示:在編程語言里,對外提供的介面(介面可理解為了一個入口),可以是函數,稱為介面函數,這與介面的概念還不一樣,介面代表一組介面函數的集合體。
#取款是功能,而這個功能有很多功能組成:插卡、密碼認證、輸入金額、列印賬單、取錢 #對使用者來說,只需要知道取款這個功能即可,其餘功能我們都可以隱藏起來,很明顯這麼做 #隔離了複雜度,同時也提升了安全性 class ATM: def __card(self): print('插卡') def __auth(self): print('用戶認證') def __input(self): print('輸入取款金額') def __print_bill(self): print('列印賬單') def __take_money(self): print('取款') def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() a=ATM() a.withdraw()