Python系列之面向对象编程
Python 面向?qū)ο缶幊?/h1>
常見(jiàn)的編程方式有三種:
1)面向過(guò)程:根據(jù)業(yè)務(wù)邏輯從上到下寫(xiě)壘代碼,最常見(jiàn)的操作就是粘貼復(fù)制,將之前實(shí)現(xiàn)的代碼塊復(fù)制到現(xiàn)需功能處。
2)函數(shù)式:將某功能代碼封裝到函數(shù)中,日后無(wú)需重復(fù)編寫(xiě),僅調(diào)用函數(shù)即可。
3)面向?qū)ο?#xff1a;對(duì)函數(shù)進(jìn)行分類和封裝,讓開(kāi)發(fā)變得更快更好更強(qiáng)。
相比于Java和C#這種只支持面向?qū)ο缶幊痰恼Z(yǔ)言,python更加靈活,既支持面向過(guò)程編程,也支持函數(shù)式編程和面向?qū)ο缶幊獭?/p>
一般在Python開(kāi)發(fā)中,通常將面向?qū)ο蠛秃瘮?shù)式混合使用,今天重點(diǎn)介紹一下Python的面向?qū)ο缶幊獭?/p>
創(chuàng)建類和對(duì)象
面向?qū)ο缶幊痰穆涞匦枰褂?“類” 和 “對(duì)象” 來(lái)實(shí)現(xiàn),所以,面向?qū)ο缶幊唐鋵?shí)就是對(duì) “類” 和 “對(duì)象” 的使用。
-
類就是一個(gè)模板,模板里可以包含多個(gè)函數(shù),用于實(shí)現(xiàn)不同的功能,這些函數(shù)也叫做 “方法” ,類中的函數(shù)第一個(gè)參數(shù)必須是self;
-
對(duì)象則是根據(jù)模板創(chuàng)建的實(shí)例,通過(guò)實(shí)例對(duì)象可以執(zhí)行類中的函數(shù)。
對(duì)比:使用函數(shù)式編程和面向?qū)ο缶幊虉?zhí)行一個(gè)“方法”
- 面向?qū)ο?#xff1a;【創(chuàng)建對(duì)象】–> 【通過(guò)對(duì)象執(zhí)行方法】
- 函數(shù)編程:【執(zhí)行函數(shù)】
對(duì)比發(fā)現(xiàn),函數(shù)式編程似乎更簡(jiǎn)便一些,實(shí)際上并非絕對(duì)。函數(shù)式編程的應(yīng)用場(chǎng)景是各個(gè)函數(shù)之間是獨(dú)立且無(wú)共用的數(shù)據(jù)。而面向?qū)ο缶幊痰膽?yīng)用場(chǎng)景是:
1)多函數(shù)使用共同的值,如:數(shù)據(jù)庫(kù)的增、刪、改、查操作都需要連接數(shù)據(jù)庫(kù)字符串、主機(jī)名、用戶名和密碼;
2)需要?jiǎng)?chuàng)建多個(gè)事物,每個(gè)事物屬性個(gè)數(shù)相同,但值不相同。
面向?qū)ο笕筇匦?/h3>
面向?qū)ο蟮娜筇匦允侵?#xff1a;封裝、繼承和多態(tài)。
一、封裝
封裝,顧名思義就是
① 將內(nèi)容封裝到某處,
② 以后再去調(diào)用被封裝的內(nèi)容。
第一步:將內(nèi)容封裝到某處
self 是一個(gè)形式參數(shù)。
當(dāng)執(zhí)行 obj1 = Foo(‘wupeiqi’, 18 ) 時(shí),self 等于 obj1;
當(dāng)執(zhí)行 obj2 = Foo(‘a(chǎn)lex’, 78 ) 時(shí),self 等于 obj2。
內(nèi)容其實(shí)被封裝到了對(duì)象 obj1 和 obj2 中,每個(gè)對(duì)象中都有 name 和 age 屬性。
第二步:從某處調(diào)用被封裝的內(nèi)容
調(diào)用被封裝的內(nèi)容時(shí),有兩種情況:
- 在類外,實(shí)例化對(duì)象之后,通過(guò)對(duì)象直接調(diào)用
- 在類中,執(zhí)行函數(shù)時(shí),通過(guò)self間接調(diào)用
1、在類外,實(shí)例化對(duì)象之后,通過(guò)對(duì)象.屬性名直接調(diào)用
class Foo:def __init__( self , name, age):self.name = nameself.age = ageobj1 = Foo('wupeiqi', 18) print(obj1.name) # 直接調(diào)用obj1對(duì)象的name屬性 print(obj1.age) #直接調(diào)用obj1對(duì)象的age屬性2、在類中,執(zhí)行函數(shù)時(shí),通過(guò)self間接調(diào)用
class Foo: def __init__( self , name, age):self.name = nameself.age = age def detail( self ):print self.nameprint self.ageobj1 = Foo( 'wupeiqi' , 18 ) obj1.detail()Python默認(rèn)將實(shí)例化的對(duì)象(obj1)傳給self參數(shù),所以方法內(nèi)部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18。
練習(xí)一:在終端輸出如下信息
-
小明,10歲,男,上山去砍柴
-
小明,10歲,男,開(kāi)車去東北
-
小明,10歲,男,最愛(ài)大保健
-
老李,90歲,男,上山去砍柴
-
老李,90歲,男,開(kāi)車去東北
-
老李,90歲,男,最愛(ài)大保健
面向?qū)ο缶幊?/strong>
函數(shù)式編程:
def kanchai(name, age, gender):print "%s,%s歲,%s,上山去砍柴" %(name, age, gender)def qudongbei(name, age, gender):print "%s,%s歲,%s,開(kāi)車去東北" %(name, age, gender)def dabaojian(name, age, gender):print "%s,%s歲,%s,最愛(ài)大保健" %(name, age, gender)kanchai('小明', 10, '男') qudongbei('小明', 10, '男') dabaojian('小明', 10, '男')kanchai('老李', 90, '男') qudongbei('老李', 90, '男') dabaojian('老李', 90, '男')可以看出,如果使用函數(shù)式編程,需要在每次執(zhí)行函數(shù)時(shí)傳入相同的參數(shù),如果參數(shù)多的話,又需要粘貼復(fù)制了… ;
而對(duì)于面向?qū)ο笾恍枰趧?chuàng)建對(duì)象時(shí),將所有需要的參數(shù)封裝到當(dāng)前對(duì)象中,之后再次使用時(shí),通過(guò)self間接去當(dāng)前對(duì)象中取值即可。
二、繼承
繼承,其實(shí)就是將多個(gè)類共有的方法提取到父類中,子類僅需繼承父類而不必一一實(shí)現(xiàn)每個(gè)方法。
注:除了子類和父類的稱謂,你可能看到過(guò) 派生類 和 基類 ,他們與子類和父類只是叫法不同而已。
例如:
貓可以:喵喵叫、吃、喝、拉、撒
狗可以:汪汪叫、吃、喝、拉、撒
如果我們要分別為貓和狗創(chuàng)建一個(gè)類,那么就需要為 貓 和 狗 實(shí)現(xiàn)他們所有的功能。
然而,吃、喝、拉、撒是貓和狗都具有的功能,如果使用 繼承 的思想,如下實(shí)現(xiàn):
動(dòng)物:吃、喝、拉、撒
貓:喵喵叫(貓繼承動(dòng)物的功能)
狗:汪汪叫(狗繼承動(dòng)物的功能)
下圖顯示了子類繼承父類 的代碼格式,就是在class 子類名稱后面的括號(hào)中寫(xiě)入父類的名稱
那么問(wèn)題又來(lái)了
Python的類可以繼承多個(gè)類,Java和C#中則只能繼承一個(gè)類
Python的類如果繼承了多個(gè)類,那么其尋找方法的方式有兩種,分別是:深度優(yōu)先和廣度優(yōu)先.
- 當(dāng)類是經(jīng)典類時(shí),多繼承情況下,會(huì)按照深度優(yōu)先方式查找
- 當(dāng)類是新式類時(shí),多繼承情況下,會(huì)按照廣度優(yōu)先方式查找
經(jīng)典類和新式類,從字面上可以看出一個(gè)老一個(gè)新,新的必然包含了跟多的功能,也是之后推薦的寫(xiě)法,從寫(xiě)法上區(qū)分的話,如果 當(dāng)前類或者父類繼承了object類,那么該類便是新式類,否則便是經(jīng)典類。
經(jīng)典類多繼承
class D:def bar(self):print 'D.bar'class C(D):def bar(self):print 'C.bar'class B(D):def bar(self):print 'B.bar'class A(B, C):def bar(self):print 'A.bar'a = A() # 執(zhí)行bar方法時(shí) # 首先去A類中查找,如果A類中沒(méi)有,則繼續(xù)去B類中找,如果B類中么有,則繼續(xù)去D類中找,如果D類中么有,則繼續(xù)去C類中找,如果還是未找到,則報(bào)錯(cuò) # 所以,查找順序:A --> B --> D --> C # 在上述查找bar方法的過(guò)程中,一旦找到,則尋找過(guò)程立即中斷,便不會(huì)再繼續(xù)找了 a.bar()新式類多繼承
class D(object):def bar(self):print 'D.bar'class C(D):def bar(self):print 'C.bar'class B(D):def bar(self):print 'B.bar'class A(B, C):def bar(self):print 'A.bar'a = A() # 執(zhí)行bar方法時(shí) # 首先去A類中查找,如果A類中沒(méi)有,則繼續(xù)去B類中找,如果B類中么有,則繼續(xù)去C類中找,如果C類中么有,則繼續(xù)去D類中找,如果還是未找到,則報(bào)錯(cuò) # 所以,查找順序:A --> B --> C --> D # 在上述查找bar方法的過(guò)程中,一旦找到,則尋找過(guò)程立即中斷,便不會(huì)再繼續(xù)找了 a.bar()三、多態(tài)
多態(tài)性是指在不考慮實(shí)例類型的情況下使用實(shí)例,不論對(duì)象千變?nèi)f化,使用者都可以通過(guò)一個(gè)統(tǒng)一的接口去調(diào)用。這么做的好處是增加了程序的靈活性和可擴(kuò)展性。
比如Python的序列類型有多種形態(tài):字符串,列表,元組,但我們可以在不考慮三者類型的前提下使用同樣的方法去計(jì)算序列的長(zhǎng)度,這就是多態(tài)性的一種體現(xiàn)。
# str,list,tuple都是序列類型 s = str('hello') l = list([1, 2, 3]) t = tuple((4, 5, 6))# 我們可以在不考慮三者類型的前提下使用s,l,t s.__len__() l.__len__() t.__len__()len(s) len(l) len(t)Pyhon不支持Java和C#這一類強(qiáng)類型語(yǔ)言中多態(tài)的寫(xiě)法,但是原生多態(tài),其Python崇尚“鴨子類型”。即‘如果看起來(lái)像、叫聲像而且走起路來(lái)像鴨子,那么它就是鴨子’。
python程序員通常根據(jù)這種行為來(lái)編寫(xiě)程序。例如,如果想編寫(xiě)現(xiàn)有對(duì)象的自定義版本,可以繼承該對(duì)象,也可以創(chuàng)建一個(gè)外觀和行為像,但與它無(wú)任何關(guān)系的全新對(duì)象,后者通常用于保存程序組件的松耦合度。
Python實(shí)現(xiàn)Java或C#的多態(tài)
class F1:passclass S1(F1):def show(self):print 'S1.show'class S2(F1):def show(self):print 'S2.show'# 由于在Java或C#中定義函數(shù)參數(shù)時(shí),必須指定參數(shù)的類型 # 為了讓Func函數(shù)既可以執(zhí)行S1對(duì)象的show方法,又可以執(zhí)行S2對(duì)象的show方法,所以,定義了一個(gè)S1和S2類的父類 # 而實(shí)際傳入的參數(shù)是:S1對(duì)象和S2對(duì)象def Func(F1 obj):"""Func函數(shù)需要接收一個(gè)F1類型或者F1子類的類型"""print obj.show()s1_obj = S1() Func(s1_obj) # 在Func函數(shù)中傳入S1類的對(duì)象 s1_obj,執(zhí)行 S1 的show方法,結(jié)果:S1.shows2_obj = S2() Func(s2_obj) # 在Func函數(shù)中傳入Ss類的對(duì)象 ss_obj,執(zhí)行 Ss 的show方法,結(jié)果:S2.show函數(shù)式編程 和 面向?qū)ο?如何選擇?分別在什么情況下使用?
答:對(duì)于 C# 和 Java 程序員來(lái)說(shuō),不存在這個(gè)問(wèn)題,因?yàn)樵搩砷T語(yǔ)言只支持面向?qū)ο缶幊?#xff08;不支持函數(shù)式編程)。而對(duì)于 Python 和 PHP 等語(yǔ)言卻同時(shí)支持兩種編程方式,且函數(shù)式編程能完成的操作,面向?qū)ο蠖伎梢詫?shí)現(xiàn);而面向?qū)ο蟮哪芡瓿傻牟僮?#xff0c;函數(shù)式編程不行(函數(shù)式編程無(wú)法實(shí)現(xiàn)面向?qū)ο蟮姆庋b功能)。
所以,一般在Python開(kāi)發(fā)中,通常將面向?qū)ο蠛秃瘮?shù)式混合使用
更多IT技術(shù)詳解和編程知識(shí)請(qǐng)關(guān)注wx公眾號(hào):DataPlanet
總結(jié)
以上是生活随笔為你收集整理的Python系列之面向对象编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 中国电信天翼物联科协分会成立,加速科技创
- 下一篇: 浅谈虚幻4引擎游戏客户端服务器及如何编译