摘要:面向?qū)ο缶幊蹋喎Q,是一種程序設(shè)計思想。面向過程與面向?qū)ο竺嫦蜻^程的程序設(shè)計把函數(shù)作為程序的基本單元。以上是在計算機(jī)世界里認(rèn)識面向?qū)ο蠛兔嫦蜻^程,接下來給大家舉個生活中的例子就拿你早上想吃雞蛋灌餅為例。
面向?qū)ο缶幊獭狾bject Oriented Programming,簡稱OOP,是一種程序設(shè)計思想。OOP把對象作為程序的基本單元,一個對象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)。面向過程 與 面向?qū)ο?/b>
面向過程的程序設(shè)計把函數(shù)作為程序的基本單元。程序設(shè)計時,編寫一組一組的函數(shù),然后一步一步按照順序的執(zhí)行各個函數(shù)。通常為了簡化程序,將大塊函數(shù)通過切割成小塊函數(shù)來降低系統(tǒng)的復(fù)雜度。
而面向?qū)ο蟮某绦蛟O(shè)計把對象作為程序的基本單元,程序設(shè)計時,設(shè)計許多的對象,每個對象都可以接收其他對象發(fā)過來的消息,并處理這些消息,計算機(jī)程序的執(zhí)行就是一系列消息在各個對象之間傳遞,各個對象調(diào)用相關(guān)的方法。
以上是在計算機(jī)世界里認(rèn)識面向?qū)ο蠛兔嫦蜻^程,接下來給大家舉個生活中的例子:
就拿你早上想吃 雞蛋灌餅 為例。
如果是面向過程去實現(xiàn)的話:
1、準(zhǔn)備食材(雞蛋 面 油 鹽 醬 生菜)
2、清洗食材(生菜)
3、和面
4、制作面餅
5、煎面餅
6、在面餅上打入雞蛋
7、雞蛋熟后,刷醬放入生菜
如果是面向?qū)ο笕崿F(xiàn)的話:
1、找到自己的女(男)朋友(對象),讓她/他去給做或者買到雞蛋灌餅。
2、如果沒有女(男)朋友,就創(chuàng)造一個唄。然后讓他幫你弄到雞蛋灌餅...
世界萬物皆對象,其實我們生成在這個世界上每天所看到接觸的都是對象,比如你的鼠標(biāo)、你的鍵盤,你的杯子,還有你其實都是對象。每個對象都有自己的屬性。再給大家補(bǔ)充一個栗子,理解為什么需要面向?qū)ο螅F(xiàn)在我們大家可以把自己看作上帝,給你一個地球你都想往里面放什么,自己想放什么放什么,首先山川、河流放好了,然后你為了讓你的地球可以豐富一點,你開始加動物,比如鳥啊,那鳥就有很多種了,百靈鳥、麻雀、火烈鳥等等,那你作為上帝是不是該累死了,每天坐那捏鳥,多無聊,你是不是想輕巧點,那怎么辦呢,你發(fā)現(xiàn)你捏的鳥把,其實也不多,我們來分析看看
鳥:顏色 形狀 會飛 會叫
那不同的可能是鳥長的不太一樣,或者叫聲不一樣,但是大部分還是一樣,上帝也累呀,于是呢就想創(chuàng)造一個鳥出來,然后不同的鳥都是在這個基礎(chǔ)上加工,這回是不是省事多了,那鳥造完了,還有魚呢,還有人
OOP編程是利用“類”和“對象”來創(chuàng)建各種模型來實現(xiàn)對真實世界的描述,使用面向?qū)ο缶幊痰脑蛞环矫媸且驗樗梢允钩绦虻木S護(hù)和擴(kuò)展變得更簡單,并且可以大大提高程序開發(fā)效率 ,另外,基于面向?qū)ο蟮某绦蚩梢允顾烁尤菀桌斫饽愕拇a邏輯,從而使團(tuán)隊開發(fā)變得更從容
面向?qū)ο蟮膸状蠛诵奶匦裕?/p>
Class 類:一個類指相同事物相同特征提取,把相同的屬性方法提煉出來定義在類中
Object 對象:一個對象是類的實例,對象是具體的,類是抽象
封裝:對外部世界隱藏對象的工作細(xì)節(jié)
繼承:一個子類繼承基類的字段和方法
多態(tài):對不同類的對象使用同樣的操作
創(chuàng)建類首先創(chuàng)建類的語法
class ClassName(object): pass
python中使用class關(guān)鍵字修飾類,類名一般采用首字母大寫,小闊號里面表示繼承,所有類最后都繼承自object。
在類中我們可以定義屬性和方法,注意這個地方有一個叫法問題,方法其實和之前寫的函數(shù)一樣,但是在類中定義的稱為方法,兩個的區(qū)別在調(diào)用的時候,方法需要特定的對象,而函數(shù)不需要
下面我們來自己寫一個簡單的類看下
class Lufei: name="蒙奇·D·路飛" age=10 def eatmeat(self): print("吃肉") l=Lufei() #實例化 print(l.name) #調(diào)用類的屬性 l.eatmeat() #調(diào)用類的方法
在eatmeat的方法參數(shù)中有一個self,這個需要注意下一定不可以省略,對于在類中定義方法的要求,就是第一個參數(shù)必須時self,除第一個參數(shù)外,類的方法和普通函數(shù)沒有什么區(qū)別,前面學(xué)會的可變參數(shù)、默認(rèn)參數(shù)、關(guān)鍵字參數(shù)等等都可以直接使用。
self的重要性不僅是__init__需要self作為第一個參數(shù),類中定義的所有方法都需要。類代碼設(shè)計為在所有對象實例間共享,self可以幫助標(biāo)示要處理哪個對象實例的數(shù)據(jù)。
python要求每個方法的第一個參數(shù)為調(diào)用對象實例,其實我們來看下下面代碼就懂了,來看下當(dāng)我們實例話后python解釋器做了什么
#我們寫的 l=Lufei() l.eatmeat() #python執(zhí)行的代碼 Lufei.__init__(l) l.eatmeat(l)理解構(gòu)造函數(shù)
class Lufei: def __init__(self,dream): print("類初始化的時候執(zhí)行__init__") self.dream=dream name="蒙奇·D·路飛" age=10 def eatmeat(self): print("吃肉"+self.dream) l=Lufei("夢想是找到傳說中的One Piece,成為海賊王") #實例化 l.eatmeat() #調(diào)用類的方法
通過上面我們來認(rèn)識一個新的方法,__init__()方法是一個特殊的方法,在對象實例化的時候調(diào)用(init表示初始化的意思,是initialization的簡寫)注意前后兩個下劃線不可以省略,這個方法也叫構(gòu)造方法
在定義類的時候,如果沒有顯示定義一個__init__()方法,程序默認(rèn)調(diào)用一個無參的__init__()方法,但是要注意,一個類中只定義一個構(gòu)造函數(shù),編寫多個實例化的時候會調(diào)用最后一個。
#正常創(chuàng)建一個類 class Bird: def fly(self): print("i can fly") print(Bird.__class__) #輸出__new__和__init區(qū)別#那么我們知道Bird其實也是一個對象,通過type這個類進(jìn)行實例化的 #通過type構(gòu)造函數(shù)來參加一個類 # def fly(self): # print("i can fly") # #type(“類名”,"基類",類的成員) # Bird=type("Bird",(object,),{"fly":fly}) b=Bird() b.fly()
class Bird: def __init__(self): print("init") #先執(zhí)行new 再執(zhí)行init def fly(self): print("fly") def __new__(self): print("new") return object.__new__(self) #如果沒有return,這個對象并沒有創(chuàng)建成功 b=Bird() b.fly()
new 用來創(chuàng)建實例,在返回的實例上執(zhí)行__init__,如果不返回實例那么__init__將不會執(zhí)行
init 用來初始化實例,設(shè)置屬性什么的
class Lufei: def __init__(self): # pass self.name="路飛" #實例變量,以self.開頭 name="蒙奇·D·路飛" #類變量 age=10 l=Lufei() #實例化 print(l.name) #訪問實例變量,輸出路飛 print(Lufei.name) #訪問類變量,輸出蒙奇·D·路飛
首先我們先來說下,實例的屬性和類屬性分別存儲在對應(yīng)的dict中,當(dāng)我們輸出查找的時候,它的順序是 實例dict->類的dict->基類
那么我們區(qū)分類變量和實例變量的目的是什么呢,他們有什么區(qū)別:很重要的一點,實例變量為每個實例獨有,類變量為所有實例共享,我們來通過修改和打印來看下
class Lufei: def __init__(self): pass # self.name="路飛" #實例變量,以self.開頭 name="蒙奇·D·路飛" #類變量 age=10 l=Lufei() #實例化 # l.name="777" Lufei.name="666" #修改的是類變量 print(l.name) #訪問實例變量 print(Lufei.name) #訪問類變量 l1=Lufei() #實例化 print(l1.name)
如果通過Lufei.name="666" 這句修改的話,則三個輸出都是 666,因為類變量作用所有實例,如果通過l.name="777"這句話修改,則只有l(wèi)這個實例輸出777,l1實例輸出蒙奇·D·路飛
類變量的用途:大家共用的屬性放在類變量中
在類中我們定義自己的屬性和方法,通過實例化后的對象,可以在外部進(jìn)行調(diào)用,但是我們也可以對屬性和方法的訪問權(quán)限進(jìn)行設(shè)置,讓外界無法訪問。
在python中實例的變量名以__開頭,就會變成私有變量(private)外部不能訪問
class Lufei: def __init__(self,dream): print("類初始化的時候執(zhí)行__init__") self.__dream=dream __name="蒙奇·D·路飛" #加__前綴變成私有變量 age=10 def eatmeat(self): print("吃肉"+self.__dream) #私有變量在外部無法訪問,內(nèi)部可以訪問 l=Lufei("夢想是找到傳說中的One Piece,成為海賊王") #實例化 print(l.__name) #報錯 "Lufei" object has no attribute "name" l.eatmeat() #調(diào)用類的方法
上面的代碼中我們可以進(jìn)行設(shè)置私有變量,那么私有變量都無法訪問了,如果想要對其進(jìn)行操作有什么方式呢,我們可以通過方法來解決,比如我們修改下私有變量為age
class Lufei: def __init__(self,dream): print("類初始化的時候執(zhí)行__init__") self.__dream=dream name="蒙奇·D·路飛" __age=10#加__前綴變成私有變量 #通過方法或者私有變量返回 def getage(self): return self.__age #通過方法對私有變量進(jìn)行賦值操作,并可以進(jìn)行數(shù)據(jù)安全驗證 def setage(self,age): if age<0: return "太小了" else: self.__age=age return "ok" def eatmeat(self): print("吃肉"+self.__dream) #私有變量在外部無法訪問,內(nèi)部可以訪問 l=Lufei("夢想是找到傳說中的One Piece,成為海賊王") #實例化 l.eatmeat() #調(diào)用類的方法 l.setage(100)#對私有變量年齡進(jìn)行設(shè)置 print(l.getage()) #獲取私有變量年齡
可以看到通過上面的代碼,我們既可以獲取到私有變量,又可以對你參數(shù)進(jìn)行安全檢查,既然變量可以,那方法是不是能設(shè)置為私有方法呢,答案肯定可以,和私有變量一樣,在名字的前面加上__即可
#定義一個私有方法 def __getdream(self): print(self.__dream) #class外界無法訪問,內(nèi)部可以同self.__getdream()訪問靜態(tài)方法、實例方法、類方法
class Bird: name="lalal" def fly(self): print("fly") print(self) #輸出: <__main__.Bird object at 0x00000000022032E8> @classmethod def eat(cls): # 一個類方法就可以通過類或它的實例來調(diào)用的方法, 不管你是用類來調(diào)用這個方法還是類實例調(diào)用這個方法,該方法的第一個參數(shù)總是定義該方法的類對象。 # 記住:方法的第一個參數(shù)都是類對象而不是實例對象 #類方法 print("eat") print(cls) #輸出:@staticmethod def sleep(): #使用靜態(tài)方法的好處是,不需要定義實例即可使用這個方法。另外,多個實例共享此靜態(tài)方法。 #使用了靜態(tài)方法,則不能再使用self #靜態(tài)方法不能訪問類變量和實例變量 # print(name)#報錯 print("sleep") b=Bird() # Bird.fly(b) 傳遞self進(jìn)去,不傳遞只是一個語法糖 b.fly() #實例方法只能被實例對象調(diào)用 # 靜態(tài)方法(由@staticmethod裝飾的方法)、類方法(由@classmethod裝飾的方法),可以被類或類的實例對象調(diào)用 b.eat() b.sleep() #可以被類或類的實例對象調(diào)用 Bird.eat() Bird.sleep() #實例方法、類方法、靜態(tài)方法區(qū)別: #1.實例方法隱含的參數(shù)為類實例self,而類方法隱含的參數(shù)為類本身cls。 #靜態(tài)方法無隱含參數(shù),主要為了類實例也可以直接調(diào)用靜態(tài)方法。 #2.靜態(tài)方法是無法訪問實例變量的 #3.類成員方法也同樣無法訪問實例變量,但可以訪問類變量; # 靜態(tài)方法有點像函數(shù)工具庫的作用,而類成員方法則更接近類似Java面向?qū)ο蟾拍钪械撵o態(tài)方法。
總結(jié)兩點:
靜態(tài)方法:無法訪問類屬性、實例屬性,相當(dāng)于一個相對獨立的方法,跟類其實沒什么關(guān)系,換個角度來講,其實就是放在一個類的作用域里的函數(shù)而已。
類成員方法:可以訪問類屬性,無法訪問實例屬性。上述的變量val1,在類里是類變量,在實例中又是實例變量,所以容易混淆。
繼承我們先來說下繼承的概念,實現(xiàn)重用的方法之一就是通過繼承機(jī)制,就像生活中,子女繼承父母的財產(chǎn),當(dāng)然也有可能是螞蟻花唄
繼承的語法,在定義好的類小括號里面寫上要繼承的類名,這個時候,被繼承的類我們稱為父類或者基類,繼承的類的稱為子類或者派生類,我們來看下具體的代碼實現(xiàn)
#父類 class Long: name="蒙奇·D·龍" def Getdream(self): print("推翻世界政府,改變世界抹去不需要人的規(guī)則。建立和諧,自由,平等,充滿夢想的世界。") #子類 class Lufei(Long): pass l=Lufei() #實例化子類 l.Getdream() #從父類繼承來的
Lufei是子類,Long是父類,子類可以繼承父類非私有的所有屬性和方法
上面代碼中屬于單繼承,python還支持多重繼承,在小括號里面可以通過都好分隔寫多個父類的名稱,需要注意的是當(dāng)多個父類的時候,python會從左到右搜索
#父類 class Long: name="蒙奇·D·龍" def Getdream(self): print("推翻世界政府,改變世界抹去不需要人的規(guī)則。建立和諧,自由,平等,充滿夢想的世界。") class Hongfa: name="香克斯" #子類 class Lufei(Long,Hongfa): pass l=Lufei() #實例化子類 print(l.name) #當(dāng)訪問的屬性兩個父類中都有定義的時候以第一個為主 l.Getdream() #從父類繼承來的
好了,我們這就完成了多重繼承,一個子類繼承了多個父類,同時獲得了多個父類的所有非私有功能
super在類的繼承中,如果重定義某個方法,該方法會覆蓋父類的同名方法,但有時,我們希望能同時實現(xiàn)父類的功能,這時,我們就需要調(diào)用父類的方法了,可通過使用 super 來實現(xiàn)
class Animal(object): def __init__(self, name): self.name = name def greet(self): print("父類中的") class Dog(Animal): def greet(self): super().greet() #通過super訪問父類中的方法 # 當(dāng)然 Python 2 里super() 是一定要參數(shù)的 super(Dog, self).greet() print("子類中的") d=Dog("旺財") d.greet()
在子類中除了super還可以通過父類名稱.方法去進(jìn)行調(diào)用,但是我們選擇super的另一個好處是他避免硬編碼和在多重繼承上面所發(fā)揮的
什么是硬編碼?硬編碼一般指在代碼中寫死的,與它相對應(yīng)的是配置項,可以在程序發(fā)布后進(jìn)行修改
MRO 列表對于支持繼承的編程語言來說,其方法(屬性)可能定義在當(dāng)前類,也可能來自于基類,所以在方法調(diào)用時就需要對當(dāng)前類和基類進(jìn)行搜索以確定方法所在的位置。而搜索的順序就是所謂的「方法解析順序」(Method Resolution Order,或MRO)。對于只支持單繼承的語言來說,MRO 一般比較簡單;而對于 Python 這種支持多繼承的語言來說,MRO 就復(fù)雜很多。
super在上面的代碼訪問父類的方法沒任何問題,那么如果是訪問父類的父類呢,我們先初始化一個場景
class A(object): def __init__(self): print("A") def show(self): print("A中的show") class B(A): def __init__(self): super().__init__() print("B") class C(A): def __init__(self): super().__init__() print("C") def show(self): #重寫了父類中的show print("C中的show") class D(B,C): def __init__(self): super().__init__() print("D")
通過上面的代碼,我們可以得到下圖
那么問題來了,這個時候 d1.show()的結(jié)果會是什么?
說會MRO,事實上,對于你定義的每一個類,Python 會計算出一個方法解析順序(Method Resolution Order, MRO)列表,它代表了類繼承的順序,我們可以使用下面的方式獲得某個類的 MRO 列表:
print(D.__mro__) #輸出(, , , , )
Python 至少有三種不同的 MRO:
1.經(jīng)典類(classic class)的深度遍歷。
經(jīng)典類采用了一種很簡單的 MRO 方法:從左至右的深度優(yōu)先遍歷。以上述「菱形繼承」為例,其查找順序為 [D, B, A, C, A],如果只保留重復(fù)類的第一個則結(jié)果為 [D,B,A,C]
2.Python 2.2 的新式類(new-style class)預(yù)計算。
3.Python 2.3 的新式類的C3 算法。它也是 Python 3 唯一支持的方式。
多態(tài)來自于希臘語,意思是有多種形式,多態(tài)意味著即使不知道變量所引用的對象類型是什么,也能對對象進(jìn)行操作,多態(tài)會根據(jù)對象的不同而表現(xiàn)出不同的行為
#父類 class Long: name="蒙奇·D·龍" def Getdream(self): print("推翻世界政府,改變世界抹去不需要人的規(guī)則。建立和諧,自由,平等,充滿夢想的世界。") #子類 class Lufei(Long): name="蒙奇·D·路飛" def Uniqueskills(self): print("三檔") #子類 class Aisi(Long): name="艾斯" def Uniqueskills(self): print("火拳") #定義父類作為參數(shù),所有的子類都可以傳參進(jìn)去 def Show(Long): Long.Uniqueskills() Show(Lufei()) #輸出三擋 Show(Aisi()) #輸出火拳
有沒有理解多態(tài),其實很簡單,多態(tài)我們不用對具體的子類型進(jìn)行了解,到底調(diào)用哪一個方法,在運行的時候會由該對象的確切類型決定,使用多態(tài),我們只管調(diào)用,不用管細(xì)節(jié)
封裝其實我們從學(xué)習(xí)函數(shù)以來都在提及封裝的概念,封裝我們可以理解為,不用管具體的實現(xiàn)細(xì)節(jié),直接調(diào)用即可,就像我們看電視,完全不用管電視是怎么播放的,只需要按下按鈕可以觀看即可
析構(gòu)函數(shù)當(dāng)使用del 刪除對象時,會調(diào)用他本身的析構(gòu)函數(shù),另外當(dāng)對象在某個作用域中調(diào)用完畢,在跳出其作用域的同時析構(gòu)函數(shù)也會被調(diào)用一次,這樣可以用來釋放內(nèi)存空間。
__del__()也是可選的,如果不提供,則Python 會在后臺提供默認(rèn)析構(gòu)函數(shù)
class Lufei: def __init__(self): self.name="路飛" def __del__(self): print("掛了")
析構(gòu)函數(shù):在實例釋放、銷毀的時候執(zhí)行、通常用于做一些收尾工作,如關(guān)閉一些數(shù)據(jù)
類中特殊成員class BigBrid: """描述類的信息""" #BigBrid.__doc__ 可以看到 name="bb" def eat(self): print("吃") def __str__(self): return "lidao" b=BigBrid() b.name="lala" print(b.__doc__) #輸出:描述類的信息 print(b.__module__)#輸出:__main__ print(b.__class__)#輸出:#__init__ 構(gòu)造方法,通過類創(chuàng)建對象時,自動觸發(fā)執(zhí)行 #__del__析構(gòu)方法,當(dāng)對象在內(nèi)存中被釋放時,自動觸發(fā)執(zhí)行。 print(BigBrid.__dict__) #獲取類的成員 輸出:{"__module__": "__main__", "__doc__": "描述類的信息", "name": "bb", "eat": , "__dict__": , "__weakref__": } print(b.__dict__) #獲取 對象b 的成員 輸出:{"name": "lala"} #__str__ 如果一個類中定義了__str__方法,那么在打印 對象 時,默認(rèn)輸出該方法的返回值。 print(b) #輸出 lidao
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/41195.html
摘要:反對者在某些領(lǐng)域?qū)Υ擞枰苑裾J(rèn)。下面再引用一段來自維基百科中關(guān)于的歷史。類的更嚴(yán)格的定義是由某種特定的元數(shù)據(jù)所組成的內(nèi)聚的包。類還可以有運行時表示形式元對象,它為操作與類相關(guān)的元數(shù)據(jù)提供了運行時支持。 在開始部分,請看官非常非常耐心地閱讀下面幾個枯燥的術(shù)語解釋,本來這不符合本教程的風(fēng)格,但是,請看官諒解,因為列位將來一定要閱讀枯燥的東西的。這些枯燥的屬于解釋,均來自維基百科。 1、問題...
摘要:今天我們介紹的主角是在類的繼承里面非常常用,它解決了子類調(diào)用父類方法的一些問題,父類多次被調(diào)用時只執(zhí)行一次,優(yōu)化了執(zhí)行邏輯,下面我們就來詳細(xì)看一下。 1 談?wù)勀銓γ嫦驅(qū)ο蟮睦斫猓?面向?qū)ο蟮木幊?--object oriented programming,簡稱:OOP,是一種編程的思想。OOP把對象當(dāng)成一個程序的基本單元,一個對象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)。面向?qū)ο蟮某霈F(xiàn)極大的提高了編...
摘要:文字有點長,對于不想看文字的朋友,可以去這里看視頻,內(nèi)容和這個文字一樣的,視頻可能更好理解面向過程概述所謂面向過程,及關(guān)注過程面向的字面意思就是關(guān)注著眼于面對著那么什么是過程呢過程就是過程,也可以理解為步驟當(dāng)我們做某件事情的時候,如果關(guān)注過 文字有點長,對于不想看文字的朋友,可以去這里看視頻,內(nèi)容和這個文字一樣的,視頻可能更好理解 https://www.piqizhu.com/v/...
摘要:這里推薦一本書源碼剖析源碼剖析豆瓣這本書把源碼中最核心的部分,給出了詳細(xì)的闡釋,不過閱讀此書需要對語言內(nèi)存模型和指針有著很好的理解。 是否非常想學(xué)好 Python,一方面被瑣事糾纏,一直沒能動手,另一方面,擔(dān)心學(xué)習(xí)成本太高,心里默默敲著退堂鼓? 幸運的是,Python 是一門初學(xué)者友好的編程語言,想要完全掌握它,你不必花上太多的時間和精力。 Python 的設(shè)計哲學(xué)之一就是...
摘要:時代,如果需要手動繼承,如多態(tài)多態(tài)是指,不同的子類對象調(diào)用相同的父類方法,會產(chǎn)生多態(tài)多樣結(jié)果的編程特性。 參考:黑馬程序員教程 - Python基礎(chǔ) 面向?qū)ο?OOP三大特性,且三個特性是有順序的: 封裝 繼承 多態(tài) 封裝 指的就是把現(xiàn)實世界的事務(wù),封裝、抽象成編程里的對象,包括各種屬性和方法。這個一般都很簡單,不需要多講。 唯一要注意的就是:推薦從小往大開始封裝、開發(fā)類。比如手槍...
閱讀 3646·2021-11-19 09:40
閱讀 3101·2019-08-30 15:54
閱讀 2320·2019-08-30 15:44
閱讀 3199·2019-08-29 15:35
閱讀 3337·2019-08-29 12:22
閱讀 2867·2019-08-28 18:01
閱讀 3148·2019-08-26 13:54
閱讀 910·2019-08-26 12:24