面向對象 Object Oriented
面向對象的學習:
- 面向對象的語法(簡單,記憶就可以搞定)
- 面向對象的思想(稍難,需要一定的理解)
面向過程和面向對象的區別
面向過程開發,以函數作為基本結構使用:
吃飯 -> 吃飯的函數
喝水 -> 喝水函數
洗衣服 -> 洗衣服的函數
睡覺 -> 使用充氣娃娃的函數
看電影 -> 買票開電影函數
....
面向對象的開發,以對象作為基本結構使用: 女朋友{ 喂飯功能 喂水功能 洗衣服功能 陪你睡覺功能 陪你看電影功能 .... }
吃飯->調用女盆友的喂飯功能
喝水->調用女朋友的喂水功能
洗衣服->調用女朋友的洗衣服功能
睡覺->調用女朋友的陪睡功能
...
面向對象的開發非常適合大型程序開發,開發速度和后期維護都比過程化開發要好很多。同時,也會降低一點效率。
語言中對象結構的特色:高內聚,低耦合。
面向對象相關的單詞:
OO 面向對象
OOP 面向對象的程序開發
OOA 面向對象的分析
OOD 面向對象的設計
OOI 面向對象的實現
OOA -> OOD -> OOI 面向對象的實現過程
類和對象
什么是類
人類就是一個類
動物類也是一個類
鳥類就是一個類
女朋友也是一個類
基友也是一個類
瓶子都是一個類
類是一個實物的特征的集合,是抽象的概念。
打蛋蛋是一個類
XXOO也是一個類
撩妹也是一個類
開車也是一個類
打人也是一個類
類也是行為和操作的概念的集合。也是不具體的操作,沒有真正操作過。
類是抽象的概念,僅此而已!
什么是對象
霍云瑞這個人他是一個對象
霍云瑞家的那個小雞雞是一個對象
霍云瑞的第一個女朋友就是一個對象
霍云瑞的當前的基友就是一個對象
這個瓶子就是一個對像。
教室后面那個空調就是一個對象。
對象就是具體存在的看得見摸得著的某個實物。
昨天霍云瑞打一次自己的蛋蛋,就是一個對象
今天中午霍云瑞吧馬浚龍XXOO了就是一個對象
今天上午霍云瑞吧馬俊龍撩了就是一個對象
馬俊龍今天晚上把霍云瑞打了,這就是一個對象
真實發生過得行為就是對象
對象一定是具體的或者發生過的事物!
類和對象的關系
類是多個對象歸納總結而來的,是一種概念,包含所有對象。
由對象總結出類的過程,叫做抽象化
對象是類的具體實現或者實施而來,他是真實的,特指某個事物
由類制作出對象的過程,叫做實例化
如何書寫類文件
推薦使用駝峰命名法來書寫文件:
駝峰命名法:
`類名:每個單詞的首字母大寫人類 Person 開車 DriveCar 撩妹 LiaoMei ....
函數名/變量:除了第一個單詞之外首字母大寫
瀧澤蘿拉 longZeLuoLa約炮函數 yuePao 或者yue_pao(不是駝峰命名)
一個文件如果是一個單獨的類,那么直接使用類名來當作文件名即可
類的組成
類中只有2種內容:成員屬性和成員方法
成員屬性:用于描述類的特征的變量就是成員屬性
成員方法:
用于描述類的功能的函數就是成員方法
類的書寫規則
1.必須使用class關鍵字來聲明一個類
2.類的名稱需要符合駝峰命名法(規范)
3.類中只能存在2種內容,成員屬性和成員方法,除此之外,所有的代碼都禁止出現!
4.聲明成員屬性時,所有成員屬性必須有值,如果沒值會報錯!,推薦使用None等值代替
5.成員方法只需要按照函數的規則聲明即可
實例化對象
實例化對象格式
對象變量 = 類()
類的類型為 type
<class 'type'>
類的值就是類本身
<class '__main__.Person'>
對象的類型為類
<class '__main__.Person'>
對象的值,對象本身
<__main__.Person object at 0x020DC650>
檢測類和對象的成員
檢測類成員
類名.__dict__
檢測對象成員
對象.__dict__
類和對象成員的操作
類成員操作
訪問類中成員類名.成員屬性名類名.成員方法名() (沒有參數要求,所有方法都可以通過類訪問)
修改類中成員
類名.成員屬性名 = 值
類名.成員方法名 = 新值 (如果需要函數只能用lambda)
刪除類中成員
del 類名.成員屬性名
del 類名.成員方法名
添加類中成員
類名.新成員屬性名 = 值
類名.新成員方法名 = 值 (如果需要函數只能用lambda)
對象成員操作
訪問對象中成員對象變量.成員屬性名對象變量.成員方法名() (必須有一個用于接收對象本身的形參)修改對象中成員對象變量.成員屬性名 = 值對象變量.成員方法名 = 新值 (如果需要函數只能用lambda)刪除對象中成員del 對象變量.成員屬性名del 對象變量名.成員方法名添加對象中成員對象變量.新成員屬性名 = 值對象變量.新成員方法名 = 值 (如果需要函數只能用lambda)
關于self
他不是關鍵字,是一個隨意書寫的字符串而已
1.英文單詞的意義 :自己
2.綁定類的方法,只能通過類來訪問的方法,就是綁定類的方法
3.非綁定類的方法,就是可以通過對象訪問的方法就是非綁定的方法
4.綁定類與非綁定類的方法不取決于語法,而取決于設計者如何設計該方法
5.一般情況下非綁定類的方法第一個參數寫單詞self,但是這不是唯一的單詞,寫什么都行,self不是關鍵字,不是關鍵字,不是關鍵字!
面向對象的三大特性
面向對象都具有三大特性:封裝,繼承 和 多態
封裝特性
封裝就是對類和對象的成員訪問進行限制,設定可以訪問的方式和不可以訪問的方式。
封裝的三個級別:
私有化封裝 -> private 英文單詞而已不是關鍵字
受保護的封裝 -> protected 英文單詞而已不是關鍵字
公共的封裝 -> public 英文單詞而不是關鍵字
檢測封裝的三個位置:
類中/對象中
類外部/對象外部
子類中
私有化封裝 private
私有化封裝是最高級別的封裝。私有化封裝之后的成員,只能在類中/對象中訪問,類的外部,子類中都不可以訪問到。
私有化封裝:在成員名稱前添加2個_即可
例如:封裝heart -> __heart
python將heart 改名為 _類名__成員名
封裝后的訪問限制:
類中/對象中 可以訪問
類外/對象外 不可以訪問
子類/子類對象 不可以訪問
注意:在python中實現的封裝操作,不是通過權限限制而是通過改名(name mangling 改名策略)實現的,名字變了找不到而已。
可以通過 對象.類名 __方法或類名.類名 __方法名訪問到(但禁止這么干)
受保護的封裝 protected
受保護的封裝是一定級別的封裝,封裝之后,只有部分位置可以訪問(類和子類),部分位置(類外)不可以訪問。
受保護的封裝: 在成員名稱前添加1個_即可
例如:受保護 money -> _money
封裝后的訪問限制:
類中/對象中 可以訪問
類外/對象外 可以訪問(原則上類外不行,但是沒實現)
子類/子類對象 可以訪問
注意:受保護的封裝依舊是通過name mangling的方式修改了成員的名稱而已。
可以通過對象.類名成員 或者類名.類名成員的方式訪問(但也別這么干)
公共的封裝 public
所有的成員默認都是公共的封裝級別,可以在類中,類外,及子類中正常訪問
類中/對象中 可以訪問
類外/對象外 可以訪問
子類/子類對象 可以訪問
繼承
繼承就是可以獲取另外一個類中的成員屬性和成員方法。(并非所有成員)
作用:繼承的作用是增加代碼的復用性,節省不必要的重復代碼,提高開發效率,同時可以設置類之間的關系。
繼承的兩個概念:
父類用于被繼承的類,稱之為父類,也叫做基類,或者超類
子類
繼承其他類的類,稱之為子類,也叫做派生類
繼承的格式
class 父類:passclass 子類(父類):#繼承操作的關鍵步驟pass
繼承的特征
1.所有類都是繼承自object類(object類對應的對象就是object對象,也是萬物皆對象)
2.子類繼承父類則可以訪問父類的所有成員。(私有成員除外)
3.子類繼承父類并不會將父類的所有成員復制到子類當中去,訪問父類成員是間接通過父類來訪問的,
4.子類可以具有自己獨有的屬性和方法
5.子類可以重載父類中的方法,只需要設置和父類指定成員相同的名稱即可實現重載,重載之后的成員,子類只會訪問當前類中的成員,而不會調用父類中同名的成員
6.子類中如果重載父類的方法,并且還想將重載的父類方法借調過來使用,可以在重載的方法中使用如下方法
[父類名.方法()](適合類) 或者 [super().方法()](適合對象)
單繼承和多繼承
單繼承:每個類只能繼承一個類的方式稱為單繼承。
多繼承:每個類可以同時繼承多個類的方式稱為多繼承。
python屬于多繼承語言!但是一般不用
多繼承格式:
class 父類1:pass
class 父類2:
pass
class 子類(父類1,父類2):
pass
多繼承之后,子類就具備了所有父類的成員(私有成員除外)
多個父類具有相同的成員時,子類繼承[繼承列表]中第一個類的方法
菱形繼承/鉆石繼承
菱形繼承格式
class A:pass
class B(A):
pass
class C(A):
pass
class D(B,C):
pass
A
/
B C
\ /
D
菱形繼承存在的問題
如果BC類同時繼承了A類,D類又繼承了BC兩個類的情況下(菱形繼承),
在調用BC中某個同名方法(該方法都繼承自A類)時會導致繼承自A類的該方法被多次調用。產生邏輯問題!
所以python使用 super() 類來解決了多繼承的菱形繼承問題
MRO列表
Method Realtion Order 用來制作一個繼承關系的列表
python3中使用C3算法來計算MRO列表(計算過程暫時忽略)
MRO列表的制作原則:
1.子類永遠在父類的前面
2.如果繼承了多個父類,那么按照()中的順序在列表中擺放
3.如果多個類同時繼承了一個父類,孫子類中只會選取第一個父類中的父類的該方法
super()
super不是一個關鍵字,也是不是有函數,他是一個類
super()的作用不是查找父類,而是找MRO列表的上一個類
super()和父類沒有任何實質性的關系,只是有時候能調用到父類而已。
在單繼承的情況下,super()永遠調用的是父類/父對象
格式:
super().方法() #python3的格式
多繼承按需操作,在沒有必要的時候避免強行使用!
mixin 設計模式
該設計模式的主要作用是采用多繼承方式,進行類的擴展。
優點:
1.mixin可以在對類不做任何修改的情況下,擴展類的功能(添加父類)
2.可以方便的組織和維護各種不同組件的劃分。
3.可以根據需要任意調整
4.可以避免創建更多的類,也可以避免繼承導致的混亂
#水果類
class Fruit:pass
#禮物類和非禮物類
class Gift:
pass
class NotGift:
pass
#南方北方類
class South:
pass
class North:
pass
#爽和不爽的蘋果
class Cool:
pass
class NotCool:
pass
#真實水果類
class Apple(Fruit,Gift,North,NotCool):
pass
class Pear(Fruit,NotGift,North,NotCool):
pass
class Banana(Fruit,NotGift,North,Cool):
pass
class Orange(Fruit,Gift,South,NotCool)
類的常用函數
issubclass()
檢測一個類是否是另外一個類的子類
格式1:issubclass(被檢測類,父類)
返回值:布爾值
格式1:issubclass(被檢測類,(父類1,父類2,父類3…))
返回值:布爾值
注意:只要有一個類是當前被檢測類的父類,那么最終結果就是True
isinstance()
檢測一個對象是否是某個類的對象格式1:isinstance(對象,類)
返回值:布爾值格式2:isinstance(對象,(類1,類2,類3...))
返回值:布爾值注意:只要一個類是當前對象的類,那么最終結果就是True
hasattr()
檢測對象/類是否具有某個成員格式:hasattr(對象/類,'成員名')
返回值:布爾值
getattr()
獲取對象/類中的成員值格式:getattr(對象,'成員名'[,成員不存在時的默認值])
返回值:成員的值
setattr()
設置或者添加對象/類中的成員格式:setattr(對象,'成員名',值)
返回值:None
delattr()
刪除對象/類中的成員格式: delattr(對象,成員)
返回值:None
dir()
獲取對象的成員名稱列表格式:dir(對象)
返回值:列表
property()
用于設置成員屬性的修飾符格式:成員屬性 = property(獲取的方法,設置的方法,刪除的方法)
描述符
python中的描述符是用于描述對象中的屬性。主要作用就是對屬性操作提供限制,驗證,管理等相關權限的操作。
描述符主要有三種操作需要設置:
get 獲取屬性的操作
set 設置屬性的操作
delete 刪除屬性的操作
描述符方法1
#描述符類
class Description:#成員屬性#name = ''#初始化方法def __init__(self):#為當前類/對象添加一個成員屬性(當前類)來接收需要描述的成員屬性(要描述的類)此處還沒有接收(占位)self.name = None#get獲取屬性值的方法def __get__(self,obj,cls):# self 用于接收當前描述符類的對象 obj 接收用于管理的成員的對象 cls 用于接收管理成員的類print('獲取方法被觸發')self.name = str(self.name)return self.name[:4]#set設置屬性值的方法def __set__(self,obj,val): #self 用于接收當前描述符類的對象 obj 接收用于管理的成員的對象 val 設置的值print('設置方法被觸發')#print(self,obj,val)#在此處可以添加限制和判斷(密碼奇數時*2)if val %2 == 1:val *= 2#完成了(email)對象的屬性值的設置self.name = val#delete刪除屬性值的方法def __delete__(self,obj): #self當前描述符類的對象 obj 接收用于管理的成員的對象#用戶代為刪除操作del self.name#聲明一個郵箱的類
class Email#屬性#用戶名account = 'conghao@zhiling.com'#密碼(為密碼設置了描述符 的對象) 這一步相當于吧password的所有傳入了Description的對象當中password = Description()
描述符方法2:
#郵箱類
class Email:#成員屬性#為username添加描述符#username = ''#設置郵箱賬號最大的長度maxlength = 6#為描述符添加一個臨時變量(在描述符中代替username進行操作)tmpusername = None password = ''#成員方法#為username的描述符進行設置(添加方法)#獲取username的描述符方法def getusername(self):print('獲取操作被觸發')#返回值之前進行值的修飾,兩邊添加星星if self.tmpusername != None:self.tmpusername = '★' + self.tmpusername + '★'#設置獲取username的時候的值return self.tmpusername#設置username的描述符方法def setusername(self,val):print('設置操作被觸發')#限制,根據Email類的最大賬號長度對用戶名進行截取之后在設置#檢測val是否是字符串類型if isinstance(val,str):val = val[0:self.maxlength]self.tmpusername = val#刪除username的描述符方法def delusername(self):print('刪除操作被觸發')#刪除操作del self.tmpusername#為username設置描述符username = property(getusername,setusername,delusername)
3.屬性修飾符
#郵箱類
class Email:#用戶名username = ''#密碼password = ''#使用描述符來操作昵稱#昵稱petname = '小乖乖'#為描述符設置臨時變量__petname = None#成員方法(暫無)#描述符設置的三個部分 獲取,設置和刪除#處理petname獲取操作@propertydef petname(self):print('獲取操作被觸發')return self.__petname#處理petname的設置操作@petname.setterdef petname(self,val):print('設置操作被觸發')#設置操作self.__petname = val#處理petname的刪除操作@petname.deleterdef petname(self):print('刪除操作被觸發')#刪除操作del self.__petname
類的內置屬性
__dict__
獲取當前類/對象成員組成的字典
__doc__
獲取當前類/對象的文檔,和函數一樣使用''' 定義即可
__name__
類.__name__是獲取當前類名,如果直接寫__name__則是獲取模塊的名稱
__bases__
獲取類的繼承列表中所有父類組成的元組