Python基础之(面向对象初识)
一、初識面向對象
1.1、面向過程的程序的核心是過程(流水線式思維),過程即解決問題的步驟,面向過程的設計就好比精心設計好一條流水線,考慮周全什么時候處理什么東西。
優(yōu)點是:極大的降低了寫程序的復雜度,只需要順著要執(zhí)行的步驟,堆疊代碼即可
缺點是:一套流水線或者流程就是用來解決一個問題,代碼牽一發(fā)而動全身,擴展性較差
1.2、面向對象的程序的核心是對象(上帝式思維),要理解對象為何物,必須把自己當成上帝,上帝眼里世間存在的萬物皆為對象,不存在的也可以創(chuàng)造出來。被上帝造出來的每個人都有各自的特征和技能(這就是對象的概念,特征和技能分別對應對象的屬性和方法)
優(yōu)點是:解決了程序的擴展性。對某一個對象單獨修改,會立刻反映到整個體系中,如對游戲中一個人物參數(shù)的特征和技能修改都很容易。
缺點:可控性差,無法向面向過程的程序設計流水線式的可以很精準的預測問題的處理流程與結果,面向對象的程序一旦開始就由對象之間的交互解決問題,即便是上帝也無法預測最終結果
面向對象的程序設計并不是全部。對于一個軟件質量來說,面向對象編程可以使程序的維護和擴展變得更簡單,并且可以大大提高程序開發(fā)效率 ,另外、基于面向對象的程序可以使他人更加容易理解你的代碼邏輯,從而使團隊開發(fā)變得更從容
1.3、類與對象
類即類別、種類,是面向對象設計最重要的概念,對象是特征與技能的結合體,而類則是一系列對象相似的特征與技能的結合體
在現(xiàn)實世界中:先有對象,再有類
在程序中:務必保證先定義類,后產生對象
實例化即是由類產生對象的過程,實例化的結果就是一個類,或者叫一個實例
?
二、類的基礎知識
2.1、創(chuàng)建一個類
''' class 類名:'類的文檔字符串'類體 ''' #與創(chuàng)建一個函數(shù)相似class Person: #創(chuàng)建一個類pass#python2中分經典類與新式類,python3中都是新式類 #經典類 class Person:pass#新式類 class Person(父類名稱):pass#申明一個新式類: class Person(object):pass2.2、屬性方法
class Person:"這是個人的類"role = "person" #數(shù)據(jù)屬性def type(self): #函數(shù)屬性(類中的方法)print("yellow race") print(Person.role) #調用屬性 Person.type(Person1) #要傳一個參數(shù)就是self實例自己,一般不這么玩,使用print(Person.type)看到這個類方法?2.3、實例化
實例化:類名加括號就是實例化,會自動觸發(fā)__init__函數(shù)的運行,可以用它來為每個實例定制自己的特征
class Person:"這是個人的類"role = "person" #數(shù)據(jù)屬性def type(self): #函數(shù)屬性(類中的方法)print("yellow race"p1 = Person() #實例化 p1.role #查看對象屬性 p1.type() #調用類方法 #補充:特殊的類屬性 類名.__name__# 類的名字(字符串) 類名.__doc__# 類的文檔字符串 類名.__base__# 類的第一個父類(在講繼承時會講) 類名.__bases__# 類所有父類構成的元組(在講繼承時會講) 類名.__dict__# 類的字典屬性 類名.__module__# 類定義所在的模塊 類名.__class__# 實例對應的類(僅新式類中)2.4、小結
class 類名:def __init__(self,參數(shù)1,參數(shù)2):self.對象的屬性1 = 參數(shù)1self.對象的屬性2 = 參數(shù)2def 方法名(self):passdef 方法名2(self):pass對象名 = 類名(1,2) #對象就是實例,代表一個具體的東西#類名() : 類名+括號就是實例化一個類,相當于調用了__init__方法#括號里傳參數(shù),參數(shù)不需要傳self,其他與init中的形參一一對應#結果返回一個對象 對象名.對象的屬性1 #查看對象的屬性,直接用 對象名.屬性名 即可 對象名.方法名() #調用類中的方法,直接用 對象名.方法名() 即可self:在實例化時自動將對象/實例本身傳給__init__的第一個參數(shù)
2.5、類和實例屬性的增刪改查
class Person:role = "person"def __init__(self, name, age):self.name = nameself.age = agedef running(self):print("%s is running" %self.name)def eat_food(self,food):print("%s eat %s" %(self.name,food))def age(self):print("%s is %s" %(self.name,self.age)) #類屬性 print(Person.role) #查看 Person.role = "dog" #修改 Person.job = "doctor" #增加 del Person.job #刪除def test(self):print("test") Person.test = test #增加#實例屬性 p1 = Person("crazy",18) print(p1.__dict__) print(p1.name) #查看 p1.job = "xxx" #增加 print(p1.__dict__)def test(self):print("test") p1.test=test p1.test(p1) #需要增加參數(shù)#實例只有數(shù)據(jù)屬性,其調用的是類的方法,但是實例也可以增加自己的方法(不同的實例去調的類方法相同,節(jié)省內存)2.6、面向對象設計,有興趣看下面一個例子:
def cl(name,age,job):def jump(cl):print("%s 正在跳" %cl["name"] )def run(cl):print("%s 今年 %s 做 %s "%(cl["name"],cl["age"],cl["job"]))def init(name,age,job):per = {"name":name,"age":age,"job":job,"run":run,"jump":jump}return perreturn init(name,age,job)c1 =cl("jojo",18,"xxx") #{'name': 'dave', 'age': 18, 'job': 'xxx', 'run': <function cl.<locals>.run at 0x02EA3930>, 'jump': <function cl.<locals>.jump at 0x02EA38E8>} c1["run"](c1) #jojo 今年 18 做 xxx?
三、面向對象三特性(封裝、繼承和多態(tài))
3.1、繼承是一種創(chuàng)建新類的方式,在python中,新建的類可以繼承一個或多個父類,父類又可稱為基類或超類,新建的類稱為派生類或子類
class Parent1: #定義父類1passclass Parent2: #定義父類2passclass Sub1(Parent1): #單繼承passclass Sub2(Parent1,Parent2): #python支持多繼承,用逗號分隔開多個繼承的類pass #查看繼承 print(Sub2.__bases__ )#(<class '__main__.Parent1'>, <class '__main__.Parent2'>)提示:如果沒有指定基類,python的類會默認繼承object類,object是所有python類的基類
3.1.1、繼承的重用
在開發(fā)過程中,如果我們定義了一個A類,然后又想新建立另外一個B類,但是類B的大部分內容與類A的相同時我們不可能從頭開始寫一個類B,這就用到了類的繼承的概念。
通過繼承的方式新建類B,讓B繼承A,B會‘遺傳’A的所有屬性(數(shù)據(jù)屬性和函數(shù)屬性),實現(xiàn)代碼重用,來看個例子:
#第一種方式 class Asia:def head(self):passdef body(self):passdef skin(self):print("yellow") class Europe:def head(self):passdef body(self):passdef skin(self):print("white") class African:def head(self):passdef body(self):passdef skin(self):print("black") #第二種方式: class Person:def head(self):passdef body(self):pass class Asia(Person):def skin(self):print("yellow") class Europe(Person):def skin(self):print("white") class African(Person):def skin(self):print("black")Python的類可以繼承多個類,Java和C#中則只能繼承一個類,Python的類如果繼承了多個類,那么其尋找方法的方式有兩種,分別是:深度優(yōu)先和C3算法(廣度優(yōu)先)
- 當類是經典類時,多繼承情況下,會按照深度優(yōu)先方式查找。
- 當類是新式類時,多繼承情況下,會按照C3算法去查詢
新式類與經典類:
- 只有在python2中才分新式類和經典類,python3中統(tǒng)一都是新式類
- 在python2中,沒有顯示繼承object類的類,以及該類的子類,都是經典類
- 在python2中,聲明繼承object的類,以及該類的子類,都是新式類
- 在python3中,無論是否繼承object,都默認繼承object,即python3中所有類均為新式類
經典類:首先去A類中查找,如果A類中沒有,則繼續(xù)去B類中找,如果B類中么有,則繼續(xù)去D類中找,如果D類中么有,則繼續(xù)去C類中找,如果還是未找到,則報錯
新式類:則根據(jù)C3算法,具體可以通過類名.mro()方法去查詢他的繼承順序。
注意:在上述查找過程中,一旦找到,則尋找過程立即中斷,便不會再繼續(xù)找
3.1.2、接口與抽象類
繼承有兩種用途:1、繼承基類的方法,并且做出自己的改變或者擴展(代碼重用)? 2、聲明某個子類兼容于某基類,定義一個接口類Interface,接口類中定義了一些接口名(就是函數(shù)名)且并未實現(xiàn)接口的功能,由子類繼承接口類,并且實現(xiàn)接口中的功能。(實踐中,繼承的第一種含義意義并不很大,甚至常常是有害的。因為它使得子類與基類出現(xiàn)強耦合)
#模擬接口 class Osname:def Windows(self): #接口函數(shù)passdef Linux(self): #接口函數(shù)passclass Win(Osname):def Windows(self):print("windows")def Linux(self):print("linx")class Lin(Osname):def Linux(self):print("linx")def Windows(self):print("windows")在python中根本就沒有一個叫做interface的關鍵字,上面的代碼只是看起來像接口,其實并沒有起到接口的作用,子類完全可以不用去實現(xiàn)接口,這就用到了抽象類。什么是抽象類?與java一樣,python也有抽象類的概念但是同樣需要借助模塊實現(xiàn),抽象類是一個特殊的類,它的特殊之處在于只能被繼承,不能被實例化
import abc #利用abc模塊實現(xiàn)抽象類 class Osname(metaclass=abc.ABCMeta):@abc.abstractmethod #定義抽象方法,無需實現(xiàn)功能def Windows(self):pass@abc.abstractmethoddef Linux(self):passclass Win(Osname): #子類繼承抽象類,但是必須定義Windows和Linux方法def Windows(self):print("windows")def Linux(self):print("linx")class Lin(Osname):def Linux(self):print("linx")def Windows(self):print("windows")class Error(Osname): pass error = Error() #報錯沒有定義方法,無法實例化3.1.5、子類中調用父類方法
- 直接父類名.方法名(self,name,addr)
-
super().方法名(name,addr)? 或者super(子類名,self).方法名()
3.1.4、類的組合與對象之間交互
軟件重用的重要方式除了繼承之外還有另外一種方式,即:組合。組合指的是,在一個類中以另外一個類的對象作為數(shù)據(jù)屬性,稱為類的組合
class Company:def __init__(self,name,addr):self.name = nameself.addr = addrself.contain = Department("技術部")class Department:def __init__(self,name):self.name = nameself.function = "打醬油"def makemoney(self):print("1毛錢1分鐘")m= Company("xx","地球") m.contain.makemoney() #1毛錢1分鐘 print(m.contain.name) #技術部組合與繼承都是有效地利用已有類的資源的重要方式,當類之間有顯著不同并且較小的類是較大的類所需要的組件時,用組合比較好
對象之間的交互,先來看個例子:
class Thishero:def __init__(self,name):self.name = name #hero名稱self.attack = 98 #攻擊值self.life = 100 #生命值def attacko(self,enemy): #enmy為敵人enemy.life-= self.attack #攻擊后敵人的生命剩余值class Otherhero:def __init__(self,name):self.name = nameself.attack = 99self.life = 100def attacko(self,enemy):enemy.life-= self.attackc1 = Thishero("關羽") c2 = Otherhero("秦瓊")c1.attacko(c2) #關羽戰(zhàn)秦瓊 print(c2.life) #秦瓊剩余生命值?3.2 多態(tài) (不同的對象執(zhí)行相同的方法,執(zhí)行的邏輯不同)
多態(tài)指的是一類事物有多種形態(tài),比如人類有亞洲人、歐洲人、外星人...文件有文本、執(zhí)行等等
class Person(metaclass=abc.ABCMeta):@abc.abstractmethoddef head(self):pass class Asia(Person):def head(self):print("yellow") class Europe(Person):def head(self):print("white") class African(Person):def head(self):print("black") asia = Asia() europe = Europe() african = African()asia.head() europe.head() african.head()def obj(obj): #我們可以定義一個統(tǒng)一的接口來使用obj.head()?其實大家從上面多態(tài)性的例子可以看出,我們并沒有增加什么新的知識,也就是說python本身就是支持多態(tài)性的。或者你說太坑了吧,多態(tài)不就是繼承嘛!
3.3、封裝,顧名思義就是將內容封裝到某個地方,以后再去調用被封裝在某處的內容。所以在使用面向對象的封裝特性時,需要:
- 將內容封裝到某處
- 從某處調用被封裝的內容
? 由此我們可以看出對于面向對象的封裝來說,其實就是使用構造方法將內容封裝到 對象 中,然后通過對象調用封裝的內容
3.3.1、封裝與擴展性
封裝在于明確區(qū)分內外,使得類實現(xiàn)者可以修改封裝內的東西而不影響外部調用者的代碼;而外部使用用者只知道一個接口(函數(shù)),只要接口(函數(shù))名、參數(shù)不變,使用者的代碼永遠無需改變。這就提供一個良好的合作基礎——或者說,只要接口這個基礎約定不變,則代碼改變不足為慮。
class Run:def __init__(self,a,b,c):self.a = aself.__b = b #(隱藏,外部可以通過接口或者直接調用)self._c = c #(只是約定隱藏,外部仍可以調用)def run(self):return (self.a*self.__b*self._c)r = Run(1,2,3) print(r.run()) print(r._c) # print(r._Run__b) #直接調用隱藏#隱藏屬性 (兩種方式外部訪問) 1、def out(self):(外部調用,接口) return __self.xxx 2、obj._類名__xxx obj._classname__xxx
轉載于:https://www.cnblogs.com/crazyjump/p/10156910.html
總結
以上是生活随笔為你收集整理的Python基础之(面向对象初识)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Django】ORM操作#2
- 下一篇: Spark RDD的默认分区数:(spa