Python面向?qū)ο缶幊?/b>
面向?qū)ο蟮木幊坍a(chǎn)生的歷史原因:由于面向過程編程在構(gòu)造系統(tǒng)時,無法解決重用锨侯,維護嫩海,擴展的問題,而且邏輯過于復(fù)雜囚痴,代碼晦澀難懂叁怪,因此,人們開始想能不能讓計算機直接模擬現(xiàn)實的環(huán)境深滚,以人類解決問題的方法奕谭,思路,習(xí)慣和步驟來設(shè)計相應(yīng)的應(yīng)用程序痴荐。于是血柳,面向?qū)ο蟮木幊趟枷刖彤a(chǎn)生了本章中,我們主要介紹面向?qū)ο缶幊蹋∣OP, object-oriented
programming)的編程思想生兆。首先介紹面向?qū)ο缶幊痰囊恍┗靖拍钅寻啤⑺枷搿⑻攸c以及使用的主要目的鸦难。然后探討類的創(chuàng)建以及使用細(xì)則和方法根吁,類屬性、對象的初始化等等合蔽。
1. 面向過程和面向?qū)ο缶幊痰幕靖拍?/p>
核心思想:面向?qū)ο蟮木幊痰闹饕枷胧前褬?gòu)成問題的各個事物分解成各個對象击敌,建立對象的目的不是為了完成一個步驟,而是為了描述一個事物在解決問題的過程中經(jīng)歷的步驟和行為拴事。對象作為程序的基本單位沃斤,將程序和數(shù)據(jù)封裝其中,以提高程序的重用性挤聘,靈活性和可擴展性轰枝。類是創(chuàng)建對象的模板,一個類可以創(chuàng)建多個對象组去。對象是類的實例化鞍陨。
面向過程的編程:函數(shù)式編程。C程序等。根據(jù)業(yè)務(wù)邏輯從上到下寫代碼
面向?qū)ο蟮木幊蹋篊++. Java, Python等诚撵。對函數(shù)進行分類和封裝缭裆,讓開發(fā)“更快更好更強
類和對象:是面向?qū)ο笾械膬蓚€重要概念
類:是對食物的抽象,比如:動物
對象:是類的一個實例寿烟,比如:貓澈驼,狗等
例如:動物可以對貓的特征和行為進行抽象,然后可以實例化為一臺真實的動物實體出來筛武。
#########
這里想放幾張圖片的缝其,傳不上去就不放了
貓(對象)???????? 動物(類)?????? 狗(對象)
#########
設(shè)計思想:現(xiàn)實世界中,任何一個操作或者是業(yè)務(wù)邏輯的實現(xiàn)都需要一個實體來完成徘六,也就是說内边,實體就是動作的支配者,沒有實體待锈,就肯定沒有動作發(fā)生漠其!
現(xiàn)在讓我們思考下,關(guān)于喝水這個動作有哪些動詞竿音?
拿杯子和屎、接水、抬手春瞬、張嘴
有動詞就一定有實現(xiàn)這個動作的實體柴信!
所謂的模擬現(xiàn)實世界,就是使計算機的編程語言在解決相關(guān)業(yè)務(wù)邏輯的方式宽气,與真實的業(yè)務(wù)邏輯的發(fā)生保持一致颠印!需要使每一個動作的背后都一個完成這個動作的實體!
因為任何功能的實現(xiàn)都是依賴于一個具體的實體的“動作|操作|行動”抹竹,可以看作是一個又一個的實體在發(fā)揮其各自的“能力”并在內(nèi)部進行協(xié)調(diào)有序的調(diào)用過程!
當(dāng)采用面向?qū)ο蟮乃枷虢鉀Q問題時止潮,可分為下面幾步:
1分析哪些動作是由哪些實體發(fā)出的窃判;
2定義這些實體,為其增加相應(yīng)的屬性和功能喇闸;
3讓實體去執(zhí)行相應(yīng)的功能或動作袄琳。
使用OOP編程的主要目的:
面向?qū)ο笫菫榱私鉀Q系統(tǒng)的可維護性,可擴展性燃乍,可重用性唆樊,我們再進一步思考,面向?qū)ο鬄槭裁茨芙鉀Q系統(tǒng)的可維護性刻蟹,可擴展性逗旁,可重用性?
面向?qū)ο螽a(chǎn)生的歷史原因有下面兩點:
1、 計算機是幫助人們解決問題的片效,然而計算機終究是個機器红伦,他只會按照人所寫的代碼,一步一步的執(zhí)行下去淀衣,最終得到了結(jié)果昙读,因此無論程序多么的復(fù)雜,計算機總是能輕松應(yīng)付膨桥,結(jié)構(gòu)化編程蛮浑,就是按照計算機的思維寫出的代碼,但是人看到這么復(fù)雜的邏輯只嚣,就無法維護和擴展了沮稚。
2、 結(jié)構(gòu)化設(shè)計是以功能為目標(biāo)來設(shè)計構(gòu)造應(yīng)用系統(tǒng)介牙,這種做法導(dǎo)致我們設(shè)計程序時壮虫,不得不將客體所構(gòu)成的現(xiàn)實世界映射到由功能模塊組成的解空間中,這種轉(zhuǎn)換過程环础,背離了人們觀察和解決問題的基本思路囚似。
可見結(jié)構(gòu)化設(shè)計在設(shè)計系統(tǒng)的時候,無法解決重用线得、維護饶唤、擴展的問題,而且會導(dǎo)致邏輯過于復(fù)雜贯钩,代碼晦澀難懂募狂。于是人們就想,能不能讓計算機直接模擬現(xiàn)實的環(huán)境角雷,用人類解決問題的思路祸穷,習(xí)慣,步驟來設(shè)計相應(yīng)的應(yīng)用程序勺三?這樣的程序雷滚,人們在讀它的時候,會更容易理解吗坚,也不需要再把現(xiàn)實世界和程序世界之間來回做轉(zhuǎn)換祈远。
與此同時,人們發(fā)現(xiàn)商源,在現(xiàn)實世界中存在的客體是問題域中的主角车份,所謂客體是指客觀存在的對象實體和主觀抽象的概念,這種客體具有屬性和行為牡彻,而客體是穩(wěn)定的扫沼,行為不穩(wěn)定的,同時客體之間具有各種聯(lián)系,因此面向客體編程充甚,比面向行為編程以政,系統(tǒng)會更穩(wěn)定,在面對頻繁的需求更改時伴找,改變的往往是行為盈蛮,而客體一般不需要改變,所以我們就把行為封裝起來技矮,這樣改變時候只需要改變行為即可抖誉,主架構(gòu)則保持了穩(wěn)定。
于是面向?qū)ο缶彤a(chǎn)生了衰倦。
然而人們追求的系統(tǒng)可維護性袒炉,可擴展性,可重用性又是怎么在面向?qū)ο笾畜w現(xiàn)出來的呢樊零?
首先看看面向?qū)ο蟮娜筇卣鳎?/p>
封裝:找到變化并且把它封裝起來我磁,你就可以在不影響其它部分的情況下修改或擴展被封裝的變化部分,這是所有設(shè)計模式的基礎(chǔ)驻襟,就是封裝變化夺艰,因此封裝的作用,就解決了程序的可擴展性沉衣。
繼承:子類繼承父類郁副,可以繼承父類的方法及屬性,實現(xiàn)了多態(tài)以及代碼的重用豌习,因此也解決了系統(tǒng)的重用性和擴展性存谎,但是繼承破壞了封裝,因為他是對子類開放的肥隆,修改父類會導(dǎo)致所有子類的改變既荚,因此繼承一定程度上又破壞了系統(tǒng)的可擴展性,所以繼承需要慎用栋艳,只有明確的IS-A關(guān)系才能使用固以,同時繼承在在程序開發(fā)過程中重構(gòu)得到的,而不是程序設(shè)計之初就使用繼承嘱巾,很多面向?qū)ο箝_發(fā)者濫用繼承,結(jié)果造成后期的代碼解決不了需求的變化了诫钓。因此優(yōu)先使用組合旬昭,而不是繼承,是面向?qū)ο箝_發(fā)中一個重要的經(jīng)驗菌湃。
多態(tài):接口的多種不同的實現(xiàn)方式即為多態(tài)问拘。接口是對行為的抽象,剛才在封裝提到,找到變化部分并封裝起來骤坐,但是封裝起來后绪杏,怎么適應(yīng)接下來的變化?這正是接口的作用纽绍,接口的主要目的是為不相關(guān)的類提供通用的處理服務(wù),我們可以想象一下蕾久。比如鳥會飛,但是超人也會飛拌夏,通過飛這個接口僧著,我們可以讓鳥和超人,都實現(xiàn)這個接口障簿,這就實現(xiàn)了系統(tǒng)的可維護性盹愚,可擴展性。
因此面向?qū)ο竽軐崿F(xiàn)人們追求的系統(tǒng)可維護性站故,可擴展性皆怕,可重用性。面向?qū)ο笫且环N編程思想西篓,起初愈腾,“面向?qū)ο蟆笔菍V冈诔绦蛟O(shè)計中采用封裝、繼承污淋、多態(tài)等設(shè)計方法顶滩,但面向?qū)ο蟮乃枷胍呀?jīng)涉及到軟件開發(fā)的各個方面,比如現(xiàn)在細(xì)分為了面向?qū)ο蟮姆治?OOA)寸爆,面向?qū)ο蟮脑O(shè)計(OOD)礁鲁,面向?qū)ο蟮木幊虒崿F(xiàn)(OOP)
2類
2.1類的聲明和創(chuàng)建
Python 類使用class關(guān)鍵字來創(chuàng)建。簡單的類聲明可以是關(guān)鍵字后緊跟類名赁豆。類聲明與函數(shù)聲明很相似仅醇,頭一行用一個相應(yīng)的關(guān)鍵字,接下來是一個作為它的定義代碼體魔种,如下所示:
?????
ClassClassName (bases)
????? Class documentation string? #類文檔字符串
????? class_suite #類體
1使用關(guān)鍵字Class定義一個類析二,并且類名的首字母要大寫;
2當(dāng)程序員需要創(chuàng)建的類型不能用簡單類型表示時就需要創(chuàng)建類节预;
3類把需要的變量和函數(shù)組合在一起叶摄,這種包含也稱之為“封裝”。
Class 類名:
?????? 成員變量
成員函數(shù)
對于Python來說安拟,聲明與定義類沒什么區(qū)別蛤吓,因為他們是同時進行的,定義(類體)緊跟在聲明(含class關(guān)鍵字的投行【header line】)和可選的文檔字符串后面糠赦。同時会傲,所有的方法必須同時被定義锅棕。
例1:
ClassRen:
????? name = “人
????? high = “cm”
????? wight = “kg”
????? def play(self)
?????????? print “LOL”
A= Ren ()
A.name= “浪輝”
A.high= :170cm”
A.weight= “100kg”
A.home= “新鄉(xiāng)”
?
?
類的方法中至少有一個參數(shù)self
定一個類:
Class Ren:
????? name = “人
????? high = “cm”
????? wight = “kg”
????? def play(self)
?????????? print “LOL”
name,high,weight為成員變量。Play為成員函數(shù)(方法)淌山。
2.2對象的創(chuàng)建:
?????? 創(chuàng)建對象的過程稱之為實例化裸燎;當(dāng)一個對象被創(chuàng)建后,包含三個方面的特性:對象的句柄泼疑、屬性和方法德绿。
?????? 句柄用于區(qū)分不同的對象
對象的屬性和方法與類中的成員變量和成員函數(shù)對應(yīng)
例:平時我們打開一個文件
Input= file (LOL, ‘r’)
這個過程既是一個實例化過程,file就是一個類王浴,只不過是系統(tǒng)定義的脆炎,不是我們自己定義的
A= Ren ()
?
即實例化一個對象,A就有屬性和方法即name等等氓辣,我們也可對屬性進行重新賦值即:
A.name= “浪輝”
A.high= :170cm”
A.weight= “100kg”
每個對象又有不同的屬性秒裕,類中沒有時,可在對象中添加屬性即
A.home= “新鄉(xiāng)”
[if !supportLineBreakNewLine]
[endif]
if __name__ == ‘__main__’: 當(dāng)這段程序直接實例化這個對象時可以執(zhí)行钞啸,當(dāng)被當(dāng)做一模塊模塊被其它程序調(diào)用時無法被執(zhí)行几蜻,這點在定義函數(shù)部分介紹有。
?
2.3 Python對象的體系結(jié)構(gòu)
?
經(jīng)典對象:內(nèi)部由屬性和方法組成体斩,屬性可以是數(shù)據(jù)類型也可以是函數(shù)類型梭稚,如屬性為函數(shù)則該屬性就是一個方法。
?????? 類的內(nèi)部方法-Python類當(dāng)中提供了一些內(nèi)部方法絮吵,方法名由前后兩個下劃線加字母組成弧烤。例如Python的構(gòu)造函數(shù)__init__
新型對象:定義新型對象,必須繼承object方法蹬敲,class_name(object) 新型對象提供了對類方法和靜態(tài)方法的支持暇昂。
2.3類的屬性
例2:
Class Digits ():
????? A=10
S = Digits ()
B = Digits ()
#第一種情況
Print S.A, B.A Digits.A
#第二種情況
S.A +=2
Print S.A, B.A Digits.A
#第三種情況
Print S.A, B.A Digits.A
#結(jié)果
情形1的結(jié)果是:10 10 10;情形2的結(jié)果是:12 10 10伴嗡;情形3的結(jié)果是:12 13 13急波;
首先為什么會有這個問題呢?因為aaa屬性被稱為類屬性瘪校,既然是類屬性澄暮,那么根據(jù)從C++/Java這種靜態(tài)語言使用的經(jīng)驗來判斷,類屬性應(yīng)該是為其實例所共享的阱扬。很自然的泣懊,既然是共享關(guān)系,那么從類的層次改變aaa的值麻惶,自然其實例的aaa的值也要跟著變化了馍刮。可是情形3的情況卻說明用踩,上面的說法是錯的渠退。錯哪里呢?
Python屬于動態(tài)強類型的語言脐彩,在很多地方和靜態(tài)語言不同碎乃,因此,不能把靜態(tài)語言的規(guī)則套到動態(tài)語言上來惠奸。其中梅誓,類屬性就是一個很好的例子。
對于屬性佛南,我們通常采用類.屬性或?qū)嵗?屬性的形式調(diào)用梗掰。
對于屬性的設(shè)置我們通常采用類.屬性= 值或?qū)嵗?屬性= 值的形式
上例中S.aaa += 2等價于S.aaa = S.aaa + 2,這句話包含了屬性獲取及屬性設(shè)置兩個操作
即Python中屬性的獲取和設(shè)置的機制與靜態(tài)語言是不同的嗅回,正是背后機制的不同及穗,導(dǎo)致了Python中類屬性不一定是為其實例所共享的,即Python屬性遵循三個規(guī)則:
1. Python中屬性的獲取是按照從下到上的順序來查找屬性绵载;
2. Python
中的類和實例是兩個完全獨立的對象埂陆;
3. Python
中的屬性設(shè)置是針對對象本身進行的;
????? 另外娃豹,類由屬性和方法組成焚虱,類的屬性是對數(shù)據(jù)的封裝,類的方法則是對類的行為的封裝懂版。類的屬性按使用范圍分為共有屬性和私有屬性鹃栽,類的屬性范圍取決于屬性的名稱
????? 共有屬性:所有共有屬性就是類中和類外調(diào)用的屬性
????? 私有屬性:不能被類以外的函數(shù)調(diào)用(可以通過instance._classname__attribute方式訪問,但只用于調(diào)試程序躯畴。定義方式以“__”雙下劃線開始的成員變量就是私有屬性民鼓,否則是公有屬性)
????? 內(nèi)置屬性:由系統(tǒng)在定義類的時候默認(rèn)添加的,由前后兩個下劃線組成__doc__等等
例2:
ClassRen:
????? name = “人
????? high = “cm”
????? wight = “kg”
????? __money = “doller”
????? def play(self)? #self名字隨意設(shè)定
?????????? print “LOL”
print self.__money
print self.name
A= Ren ()
A.name= “浪輝”
A.high= :170cm”
A.weight= “100kg”
A.home= “新鄉(xiāng)”
Ren.high
High,weight,name為公有屬性私股,__money為私有屬性摹察,只能在類內(nèi)部通過內(nèi)部方法使用。這樣實現(xiàn)對數(shù)據(jù)的隱藏倡鲸,便于封裝供嚎。
另外,可通過A.__Ren__money的方法訪問私有屬性峭状,但是一般不建議使用克滴,通常在測試的時候用。
一些特殊屬性即內(nèi)置屬性:
C.__name__:類C的名字(字符串)
C.__doc__:類C的文檔字符串
C.__bases__:類C的所有父類構(gòu)成的元組
C.__dict__:類C的屬性
2.3類的方法
例3:
ClassRen:
????? name = “人
????? high = “cm”
????? wight = “kg”
????? __money = “doller”
?????
def play(self)?#self名字隨意設(shè)定
?????????? print “LOL”
print self.__money
print self.name
print self.__say()
def __say(self):
????? print“I love xxx”
?????
def School (self)
????? print“湖大皇子”
b = classmethod(School)
?
def Student()
????? print“大鵬”
c = staticmethod(Student)
?
A= Ren ()
A.name= “浪輝”
A.high= “170cm”
A.weight= “100kg”
A.home= “新鄉(xiāng)”
Ren.high
公有方法:類的方法共有方法不能被類直接調(diào)用优床,需要實例化對象去調(diào)用
私有方法:不能被外部的類和方法調(diào)用劝赔,私有方法的定義和私有屬性的定義都是一樣的,在方法的前面加上”__“雙下劃線就可以了胆敞;
類方法:被classmethod()函數(shù)處理過的函數(shù)着帽,能被類所調(diào)用杂伟,也能被對象所調(diào)用(是繼承的關(guān)系);
靜態(tài)方法:相當(dāng)與”全局函數(shù)“仍翰,可以被類直接調(diào)用赫粥,可以被所有實例化對象共享,通過staticmethod()定義靜態(tài)方法予借,不需要”self“語句
上例中的def play(self)為公有方法越平,可在類中被調(diào)用或被實例化調(diào)用,但是不能被類直接調(diào)用灵迫。def __say(self) 為私有方法秦叛,只能在類中被調(diào)用。def School (self)是類方法瀑粥,可被類直接調(diào)用挣跋,也可被對象調(diào)用。def Student()為靜態(tài)方法利凑,用法同類方法一樣浆劲。
類方法和靜態(tài)方法使用上是相同的,但是原理上是有區(qū)別的哀澈。
1靜態(tài)方法不需要加self
2靜態(tài)方法是調(diào)用時會預(yù)先將類中用到屬性和方法進行加載牌借,而類方法則是隨調(diào)隨用。因此類方法相比靜態(tài)方法不占資源割按,但是速度不及靜態(tài)方法膨报。
3靜態(tài)方法調(diào)用類中的屬性時需要?? 類名.屬性
?
????? 另外,Python有一個裝飾器功能适荣,即在一個方法前加上”@classmethod“或”@staticmethod“可快速將此方法設(shè)置為類方法或靜態(tài)方法现柠。
參考資料:
Python核心編程
https://www.cnblogs.com/seesea125/archive/2012/04/03/2431176.html
https://www.cnblogs.com/zln1021/p/6070591.html
https://blog.csdn.net/jianyuerensheng/article/details/51602015
http://python.jobbole.com/85100/