oop三大特征:繼承,、多態(tài),、封裝
1、概念
面向過程:一開始學(xué)習(xí)的,,按照解決問題的步驟編程【根據(jù)業(yè)務(wù)邏輯從上到下編程】
函數(shù)式:將某功能代碼封裝到函數(shù)中,,下次使用直接調(diào)用,無需重復(fù)編寫
面向?qū)ο缶幊蹋簩?shù)據(jù)與函數(shù)綁在一起封裝,,這樣能夠更快速的開發(fā)程序,,減少重復(fù)代碼的重寫過程 oop(object oriented programming),是一種解決軟件復(fù)用的設(shè)計(jì)和編程方法,,這種方法將軟件系統(tǒng)中相近相似的操作邏輯和操作應(yīng)用數(shù)據(jù),、狀態(tài),以類的形式描述出來,,以對(duì)象實(shí)例的形式在軟件系統(tǒng)中復(fù)用,,以達(dá)到提高軟件開發(fā)效率的作用
面向過程適合做小項(xiàng)目,面向?qū)ο筮m合做大項(xiàng)目
2,、類和對(duì)象
2.1 概念
類:一個(gè)模板,,模板里包含多個(gè)函數(shù),函數(shù)中實(shí)現(xiàn)一些功能(汽車圖紙,、車類)
是一組具有相同或相似屬性和行為的多個(gè)對(duì)象的組合
對(duì)象:類的實(shí)例化,,可以執(zhí)行類中的函數(shù)(寶馬)
2.2 定義類和創(chuàng)建對(duì)象
定義類:類結(jié)構(gòu)=類名(首字母大寫)+屬性+方法行為
實(shí)例方法:在類內(nèi)部,,用def可以定義實(shí)例方法,,與一般函數(shù)不同的是實(shí)例方法必須包含參數(shù),默認(rèn)第一個(gè)參數(shù)是self(名字標(biāo)識(shí)可以是其他名字,但這個(gè)位置必須被占用)
parms.name='小紅'#實(shí)例屬性
創(chuàng)建對(duì)象:
格式:對(duì)象名=類名()
#創(chuàng)建對(duì)象[類的實(shí)例化]
print('{}的年齡是:{}歲'.format(xm.name,xm.age))
屬性:
- 類屬性:類對(duì)象所擁有的屬性(定義在類內(nèi)部,,實(shí)例方法外)
- 實(shí)例屬性:實(shí)例對(duì)象擁有的屬性,,只能通過實(shí)例對(duì)象訪問(實(shí)例方法內(nèi)定義的【通過類似于self.變量名】變量)
print(lm.name)#類屬性可以被類對(duì)象和實(shí)例對(duì)象訪問
print(lm.age)#實(shí)例屬性只能通過實(shí)例對(duì)象訪問
print('不能通過類對(duì)象訪問實(shí)例屬性')
# 不能通過類對(duì)象訪問實(shí)例屬性
# Traceback (most recent call last):
# File "E:\資源下載\workspace\shixun\pythonProject2\2.17多態(tài).py", line 47, in <module>
# AttributeError: type object 'Student' has no attribute 'age'
類屬性和實(shí)例屬性的訪問原理:
2.3 __init__(self):
Python自帶的內(nèi)置函數(shù)
是一個(gè)初始化方法,用來定義實(shí)例屬性和初始化數(shù)據(jù),,在創(chuàng)建對(duì)象時(shí)自動(dòng)調(diào)用
xq=Person()#創(chuàng)建新對(duì)象時(shí),,__init__自動(dòng)調(diào)用
傳遞參數(shù)(后面實(shí)例方法都可以直接使用該參數(shù))
def __init__(self,name,age):
print(self.name+'喜歡吃'+food)
2.4 self的理解
self和對(duì)象指向同一內(nèi)存地址,self是對(duì)象的引用,,可以理解為對(duì)象自己
print('self=%s',id(self))
- self只有在類中定義實(shí)例方法時(shí)才有意義,,在調(diào)用時(shí)不必傳入相應(yīng)參數(shù),而是由解釋權(quán)自動(dòng)指向
- self的名稱可以更改,,只是約定俗成的定義成了self
- self指的是類實(shí)例對(duì)象本身
self傳參:
def eat(self,name,food,pro):
print('%s喜歡吃%s,,修的專業(yè)是%s,%s'%(name,food,self.pro,pro))
# 小明喜歡吃榴蓮,修的專業(yè)是通信工程,hhh
3,、魔術(shù)方法
定義:Python中的一些內(nèi)置好的特定方法,,方法名為“__xxx__”,前后有兩個(gè)下劃線
- 在進(jìn)行特定操作時(shí),,魔術(shù)方法會(huì)自動(dòng)調(diào)用
常見的魔術(shù)方法:
3.1__str__()
定義了__str__方法,,在打印對(duì)象時(shí),會(huì)執(zhí)行__str__方法(__str__只能return一個(gè)字符串)
def __init__(self,name,colour):
return '我的名字是%s,,我的顏色是%s'%(self.name,self.colour)
dog=Animal('旺財(cái)','白色')
def __init__(self,name,colour):
dog=Animal('旺財(cái)','白色')
# <__main__.Animal object at 0x000001E49FEF6FD0>
3.2 __new__()
調(diào)用對(duì)象實(shí)例的方法,每調(diào)用一次生成一個(gè)新對(duì)象,,cls是class的縮寫
def __init__(self,name,colour):
print('__init__函數(shù)執(zhí)行')
return '我的名字是%s,,我的顏色是%s'%(self.name,self.colour)
def __new__(cls, *args, **kwargs):
print('__new__函數(shù)執(zhí)行')
# return object.__new__(cls)#這里真正創(chuàng)建對(duì)象實(shí)例
dog=Animal('旺財(cái)','白色')
def __init__(self,name,colour):
print('__init__函數(shù)執(zhí)行')
return '我的名字是%s,我的顏色是%s'%(self.name,self.colour)
def __new__(cls, *args, **kwargs):
print('__new__函數(shù)執(zhí)行')
return object.__new__(cls)#這里真正創(chuàng)建對(duì)象實(shí)例
# return super().__new__(cls)#若沒有父類object,用super()創(chuàng)建對(duì)象實(shí)例
dog=Animal('旺財(cái)','白色')
#先執(zhí)行__new__(),,創(chuàng)建對(duì)象實(shí)例后執(zhí)行__init__
#__new__()創(chuàng)建實(shí)例框架,__init__豐滿
__new__方法在__init__方法前執(zhí)行
__new__方法不能調(diào)用自己的__new__方法,,即:return cls.__new__(cls)
- 否則會(huì)報(bào)錯(cuò):RecursionError:maximum recursion depth exceeded超過最大遞歸深度
__new__和__init__的區(qū)別
- __new__:類的實(shí)例化方法,,必須返回該實(shí)例,不然對(duì)象創(chuàng)建不成功
- __init__:做對(duì)象的初始化工作,,也可以認(rèn)為是實(shí)例的構(gòu)造方法,,接受該實(shí)例self并對(duì)其構(gòu)造
- __new__至少一個(gè)參數(shù)是cls,代表要實(shí)例化的類,,該參數(shù)在實(shí)例化時(shí)由Python解釋器自動(dòng)提供
- __new__要早于__init__函數(shù)執(zhí)行
課后問答
4,、析構(gòu)方法
當(dāng)一個(gè)對(duì)象被刪除或銷毀時(shí),Python解釋器默認(rèn)調(diào)用__del__()方法,,這個(gè)方法也稱析構(gòu)方法,,也是一種魔術(shù)方法
- 用于對(duì)象的釋放,,對(duì)象一旦被釋放,不能再使用
程序執(zhí)行結(jié)束自動(dòng)調(diào)用__del__()
對(duì)象被刪除時(shí),,也會(huì)自動(dòng)調(diào)用__del__方法
del cat#手動(dòng)去清理對(duì)象
5,、類的繼承*
Python面向?qū)ο蟮娜筇卣鳎悍庋b、繼承,、多態(tài)
封裝:把內(nèi)容封裝到某個(gè)地方,,便于后面的使用【其實(shí)就是使用初始化構(gòu)造方法將內(nèi)容封裝到對(duì)象中,然后通過對(duì)象直接或者self來獲取封裝的內(nèi)容】
繼承:即子可以繼承父的內(nèi)容(屬性和行為)
- 將多個(gè)類共有的方法提取到【父類】中,,然后通過繼承,,極大提高了效率,減少代碼的重復(fù)編寫
5.1 單繼承
5.2 多繼承
子類繼承多個(gè)父類,,用逗號(hào)分隔 class C(A,B)
問題是:當(dāng)多個(gè)父類中存在相同方法時(shí),,應(yīng)該調(diào)用哪一個(gè)呢?
a1.eat()#查找順序,,A中沒有,,找B,B中沒有,,找C
# (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)
__mro__方法:查詢執(zhí)行順序
繼承的傳遞性:爸爸繼承了爺爺,,兒子繼承爸爸,也繼承了爺爺
5.3 重寫和調(diào)用父類方法
子類中有個(gè)跟父類方法名稱一樣的方法,,相當(dāng)于重寫父類方法(方法覆蓋)
重寫父類方法后,,子類調(diào)用父類方法時(shí),調(diào)用的是子類的方法
# (<class '__main__.Son'>, <class '__main__.Father'>, <class 'object'>)
調(diào)用父類方法
def __init__(self,name,color):
def __init__(self,name,color,age):#重寫父類方法
# Dog.__init__(self,name,color)#調(diào)用父類方法1--手動(dòng)調(diào)用
super().__init__(name,color)#調(diào)用父類方法2--自動(dòng)調(diào)用:super()自動(dòng)查找父類方,進(jìn)而調(diào)用方法
super().bark()#調(diào)用父類方法
print('名字:%s,,顏色:%s,年齡:%s'%(self.name,self.color,self.age))
super():假如繼承了多個(gè)父類,則會(huì)按順序查找
def __init__(self,name,color,age):#重寫父類方法
# Dog.__init__(self,name,color)#調(diào)用父類方法1
super().__init__(name,color)#調(diào)用父類方法2:super()自動(dòng)查找父類方,進(jìn)而調(diào)用方法
super().bark()#調(diào)用父類方法
print('名字:%s,,顏色:%s,年齡:%s'%(self.name,self.color,self.age))
6、多態(tài)
定義:就是多種狀態(tài)(形態(tài)),,就是同一種行為,,對(duì)于不同子類【對(duì)象】有不同的行為表現(xiàn)
想實(shí)現(xiàn)多態(tài)必須滿足的兩個(gè)條件:
- 繼承:多態(tài)必須發(fā)生在父態(tài)和子態(tài)之間
- 重寫:子類重寫父類方法
作用:增加程序的靈活性和擴(kuò)展性
鴨子類型:在程序設(shè)計(jì)中,鴨子類型是動(dòng)態(tài)類型的一種風(fēng)格,?!傍喿訙y(cè)試”可以表述為:“當(dāng)一個(gè)鳥走起來像鴨子,叫起來像鴨子,,那么這只鳥可以稱為鴨子”
7,、類方法和靜態(tài)方法
類方法:類對(duì)象所擁有的方法,用裝飾器@classmate標(biāo)識(shí),,類方法的第一個(gè)參數(shù)必須是類對(duì)象,,一般以cls作為第一個(gè)參數(shù)。
可以通過類對(duì)象,、實(shí)例對(duì)象調(diào)用
def change_name(cls,new_name):
cls.name=new_name#在類方法中修改類屬性的值
print(Student.get_name())#類對(duì)象引用
print(lh.get_name())#實(shí)例對(duì)象引用
Student.change_name("小花")
print(Student.get_name())#類對(duì)象引用
print(xh.get_name())#實(shí)例對(duì)象引用
靜態(tài)方法:類對(duì)象所擁有的方法,,需要用@staticmethod來表示靜態(tài)方法
print(Student.getdate())#類對(duì)象引用
print(lh.getdate())#實(shí)例對(duì)象引用
靜態(tài)方法一般不會(huì)通過實(shí)例對(duì)象訪問
為什么使用靜態(tài)方法,?
靜態(tài)方法主要用來存放邏輯性代碼,在靜態(tài)方法中,,不會(huì)涉及到類中方法和屬性的操作,,數(shù)據(jù)資源能得到有效利用
return time.strftime("%H:%M:%S",time.localtime())
print(Timetest.showtime())
- 類方法的第一個(gè)參數(shù)是類對(duì)象cls,進(jìn)而去引用類對(duì)象的屬性和方法
- 實(shí)例方法的第一個(gè)參數(shù)必須是self,,通過self去引用類屬性或?qū)嵗龑傩?,若存在相同名稱實(shí)例屬性和類屬性,實(shí)例屬性優(yōu)先級(jí)最高
- 靜態(tài)方法不需要定義額外參數(shù),,需要引用屬性時(shí),,可通過類對(duì)象或?qū)嵗龑?duì)象去引用
8、私有化屬性和方法--保護(hù)和控制數(shù)據(jù)
8.1私有化屬性
保護(hù)屬性安全,,不得隨意修改,,將屬性定義成私有化屬性,添加可調(diào)用的方法去訪問
使用私有化屬性的場(chǎng)景:
- 把特定屬性隱藏,,不想讓類的外部直接調(diào)用(不能在外部直接訪問,,在類的內(nèi)部可以隨意訪問)
- 保護(hù)這個(gè)屬性,不想讓該屬性的值隨意改變(內(nèi)部可以修改)
- 保護(hù)屬性,,不想讓派生類【子類】去繼承(子類不能繼承父類的私有屬性)
語法:兩個(gè)下劃線開頭,,聲明屬性為私有屬性,不能在類的外部被使用或直接訪問
self.__age=18#屬性私有化(外部不能訪問,,內(nèi)部可以訪問)
return('{}的年齡是{}'.format(self.name,self.__age))
print(x1.__age)#通過類對(duì)象在外部訪問(私有化后,,不能在外部直接訪問)
# Traceback (most recent call last):
# File "E:\資源下載\workspace\shixun\pythonProject2\2.17多態(tài).py", line 125, in <module>
# print(x1.__age)#通過類對(duì)象在外部訪問(私有化后,不能在外部直接訪問)
# AttributeError: 'Person' object has no attribute '__age'
8.2 私有化方法
語法:方法名前加兩個(gè)下劃線
- 私有化的方法不能被【子類】繼承
- 外部不能直接調(diào)用,,內(nèi)部可以調(diào)用
__xxx:方法私有化
__xxx__:魔術(shù)方法,,Python自有,開發(fā)者不要?jiǎng)?chuàng)建
xxx_:避免屬性名與Python關(guān)鍵字沖突
9,、property屬性函數(shù)
讓調(diào)用者能直接以訪問屬性的方式,,而且又能控制的方式
實(shí)現(xiàn)方法1-- 類屬性
def chance(self,age):#修改私有實(shí)例屬性
#定義一個(gè)類屬性,實(shí)現(xiàn)直接訪問屬性的形式去訪問私有的屬性
實(shí)現(xiàn)方法2:裝飾器*
即在方法上使用裝飾器
@property#通過裝飾器修飾添加屬性標(biāo)志,,提供一個(gè)getter方法
@dog.setter#提供一個(gè)setter方法
def chance(self,parms):#修改私有實(shí)例屬性
10,、__new__方法(參考3.2)和單例模式
單例模式:一種常用的軟件設(shè)計(jì)模式
目的:確保某個(gè)類中只有一個(gè)實(shí)例存在
實(shí)現(xiàn)步驟:利用類屬性保存初次創(chuàng)建的實(shí)例對(duì)象,第二次實(shí)例化對(duì)象的時(shí)候判斷類屬性是否保存實(shí)例對(duì)象,,如果有就返回類屬性保存的,,如果沒有就調(diào)用父類__new__方法創(chuàng)建新的實(shí)例對(duì)象
def __init__(self,name,age):
def __new__(cls, *args, **kwargs):
cls.__instance=super(Student,cls).__new__(cls)#沒有保存實(shí)例,就保存
#id相同,,說明實(shí)例化兩次對(duì)象,,都是同一對(duì)象
11、異常處理
語法格式:
不管有沒有出錯(cuò)都要執(zhí)行的代碼塊
Python內(nèi)置異常類型:
Exception:萬能類型,、可以捕獲所有異常
自定義異常
- 要直接或間接繼承Error或Exception
- 用raise關(guān)鍵字拋出異常
class Toolong(Exception):
return '你的長度為%s,過長了,。,。'%self.leng
name=input('請(qǐng)輸入你的名字:')
12,、動(dòng)態(tài)添加屬性和方法
動(dòng)態(tài)語言能在運(yùn)行時(shí)改變其結(jié)構(gòu);Python,、php,、JavaScript是動(dòng)態(tài)語言,c,、c#、Java是靜態(tài)語言
所有,,Python在程序運(yùn)行過程中添加屬性和方法
12.1 動(dòng)態(tài)添加屬性
def __init__(self,name,age):
print('%s 年齡:%s'%(self.name,self.age))
cat.color='花色'#給對(duì)象動(dòng)態(tài)添加屬性
Animal.color='白色'#給類動(dòng)態(tài)添加屬性
12.2動(dòng)態(tài)添加方法(需要用到types模塊)
語法:
實(shí)例名.引入方法的新名字=types.MethodType(方法名,實(shí)例名)#動(dòng)態(tài)添加方法
實(shí)例名.引入方法的新名字()#調(diào)用新方法
print("%s 歲的%s在跑,。。"%(self.age,self.name))
def __init__(self,name,age):
cat.run=types.MethodType(run,cat)#動(dòng)態(tài)添加方法
#2 歲的小貓?jiān)谂??!?/div>
12.3 動(dòng)態(tài)綁定類方法和靜態(tài)方法
語法:類名.新名字=類方法名
print("這是個(gè)靜態(tài)方法")
#動(dòng)態(tài)給類添加類方法、靜態(tài)方法
Animal.classnewname=classTest
Animal.staticnewname=staticTest
13,、__slots__屬性
作用:限制可以添加的實(shí)例屬性
__slots__ = ('name','age','weight')#限制添加的屬性
return '%s 。,。,。%s'%(self.name,self.age)
# xh.height 被限制,運(yùn)行會(huì)報(bào)錯(cuò)
__dict__:所有可用的屬性都存儲(chǔ)在這,,占用內(nèi)存高,;使用__slots__后,實(shí)例中不再有__dict__
# __slots__ = ('name','age','weight')#限制添加的屬性
return '%s ,。,。。%s'%(self.name,self.age)
# xh.height 被限制,,運(yùn)行會(huì)報(bào)錯(cuò)
print(xh.__dict__)#沒有設(shè)置__slots__時(shí),,所有可用的屬性存儲(chǔ)在這
# {'name': '小花', 'age': 20, 'weight': 45}
slots的作用:限制實(shí)例的屬性,;節(jié)約內(nèi)存空間
子類繼承父類時(shí),若不聲明slots,,不繼承父類的slots,;聲明slots后,子類限制屬性=父類+自身
__slots__ = ('name','age','weight')#限制添加的屬性
return '%s ,。,。。%s'%(self.name,self.age)
__slots__ = ('color')#未聲明時(shí),,不繼承父類__slots__,,聲明后,限制屬性=父類+自身