一、面向?qū)ο?,這個對象到底是什么?
這個對象不是python中的實(shí)例,python中我們把一個類的實(shí)例也叫做對象,這種對象嚴(yán)格的說應(yīng)該是面向?qū)ο蟮木幊虒?shí)現(xiàn)(OOP)中的對象,面向?qū)ο缶幊?,也不是面向類的?shí)例編程。對象的定義是人們要進(jìn)行研究的任何事物,從最簡單的整數(shù)到復(fù)雜的飛機(jī)等均可看作對象,它不僅能表示具體的事物,還能表示抽象的規(guī)則、計劃或事件。也有的定義為“一切都是對象”然而面向?qū)ο笠膊荒芎唵蔚牡葍r理解成面向任何事物編程,面對一切編程?開玩笑,呵呵。
因此面向?qū)ο筮@個對象,指的是客體。所謂客體是指客觀存在的對象實(shí)體和主觀抽象的概念。
二、面向?qū)ο蟪绦蛟O(shè)計的由來
1、編程語言的發(fā)展
程序設(shè)計這東西一開始出現(xiàn),是按照人類的語言習(xí)慣,將盡量符合人類語言的語法結(jié)構(gòu)來描述要實(shí)現(xiàn)的功能,然后通過各種軟件環(huán)境[XX語言編譯器、XX語言解釋器]將這樣符合人類語言的語法編譯或者解釋成計算機(jī)能認(rèn)識和執(zhí)行的語言去執(zhí)行并實(shí)現(xiàn)功能的過程,于是出現(xiàn)了高級語言。
2、面向過程的程序設(shè)計
高級語言出現(xiàn)之初,程序設(shè)計的思路,也是參考了人類解決問題的思路;
遇到一個問題,人類習(xí)慣性的思維方式是第一步做什么、第二步做什么、緊接著做什么,這樣按照一定的步驟一直到實(shí)現(xiàn)最終想要的功能。
這樣的按照事情/功能的處理過程和步驟來進(jìn)行程序的設(shè)計和開發(fā)的過程,是一種解決問題的思路,我們稱之為:面向過程的程序設(shè)計
3、面向過程程序設(shè)計的缺陷
面向過程的程序設(shè)計發(fā)展了一定的時間之后,我們發(fā)現(xiàn)出現(xiàn)了一個非常重要的問題,如果僅僅是處理某一個功能的流程而言非常適合,但是如果一旦涉及到業(yè)務(wù)過程比較復(fù)雜的系統(tǒng)來說的話,面向過程的思路設(shè)計的程序出現(xiàn)了大量的代碼冗余、同時不同的功能之間的沖突隨著系統(tǒng)功能的增多沖突越來越多,另外當(dāng)系統(tǒng)中的某些功能如果需要升級或者改動,會涉及到大量的代碼的修改和功能的影響造成維護(hù)的不方便
4、面向?qū)ο?/p>
這時候,一幫大佬們圍坐在一起,開始商量怎么樣讓我們的程序更加適合開發(fā)結(jié)構(gòu)完整、流程復(fù)雜的系統(tǒng)項(xiàng)目呢!
有人就提出了,我們的程序,其實(shí)一直都是在模擬符合正常人的思維邏輯習(xí)慣的,小功能的處理就像我們處理一件小事一樣,可以按照步驟進(jìn)行處理,也就是按照面向過程的設(shè)計思路進(jìn)行處理;
三、首先看看面向?qū)ο蟮娜筇卣鳎?/b>
封裝:將對象的敏感的信息封裝在對象的內(nèi)部,不讓外界直接訪問,提高數(shù)據(jù)的安全性
繼承:通過繼承關(guān)系,梳理對象和對象之間的關(guān)系,同時提高了程序設(shè)計功能的強(qiáng)大的擴(kuò)展性和代碼的復(fù)用性
多態(tài):程序在運(yùn)行過程中,實(shí)時根據(jù)不同的數(shù)據(jù)執(zhí)行不同的處理邏輯展現(xiàn)不同的狀態(tài),讓程序的功能更加的完善健壯
因此面向?qū)ο竽軐?shí)現(xiàn)人們追求的系統(tǒng)可維護(hù)性,可擴(kuò)展性,可重用性。面向?qū)ο笫且环N編程思想,起初,“面向?qū)ο蟆笔菍V冈诔绦蛟O(shè)計中采用封裝、繼承、多態(tài)等設(shè)計方法,但面向?qū)ο蟮乃枷胍呀?jīng)涉及到軟件開發(fā)的各個方面,比如現(xiàn)在細(xì)分為了面向?qū)ο蟮姆治?OOA),面向?qū)ο蟮脑O(shè)計(OOD),面向?qū)ο蟮木幊虒?shí)現(xiàn)(OOP)
四、面對對象編程,分為幾個步驟?
面向?qū)ο笫且环N思想,他讓我們在分析和解決問題時,把思維和重點(diǎn)轉(zhuǎn)向現(xiàn)實(shí)中的客體中來,然后通過工具理清這些客體之間的聯(lián)系,最后用面向?qū)ο蟮恼Z言實(shí)現(xiàn)這種客體以及客體之間的聯(lián)系。它分為面向?qū)ο蟮姆治?OOA),面向?qū)ο蟮脑O(shè)計(OOD),面向?qū)ο蟮木幊虒?shí)現(xiàn)(OOP)三個大的步驟。
1、首先是分析需求,先不要思考怎么用程序?qū)崿F(xiàn)它,先分析需求中穩(wěn)定不變的客體都是些什么,這些客體之間的關(guān)系是什么。
2、把第一步分析出來的需求,通過進(jìn)一步擴(kuò)充模型,變成可實(shí)現(xiàn)的、符合成本的、模塊化的、低耦合的模型。
3、使用面向?qū)ο蟮膶?shí)現(xiàn)模型
五、面向過程到面向?qū)ο笏季S如何轉(zhuǎn)變?
當(dāng)我們習(xí)慣了面向過程編程時,發(fā)現(xiàn)在程序過程中到處找不到需要面向?qū)ο蟮牡胤?,最主要的原因,是思維沒有轉(zhuǎn)變。程序員通常在拿到一個需求的時候,第一個反應(yīng)就是如何實(shí)現(xiàn)這個需求,這是典型的面向過程的思維過程,而且很快可能就實(shí)現(xiàn)了它。而面向?qū)ο?,面對的卻是客體,第一步不是考慮如何實(shí)現(xiàn)需求,而是進(jìn)行需求分析,就是根據(jù)需求找到其中的客體,再找到這些客體之間的聯(lián)系。因此面向過程和面向?qū)ο蟮乃季S轉(zhuǎn)變的關(guān)鍵點(diǎn),就是在第一步設(shè)計,拿到需求后,一定先不要考慮如何實(shí)現(xiàn)它,而是通過建模,然后按照模型去實(shí)現(xiàn)它。這種思路的轉(zhuǎn)變,可能需要個過程。
六、Python3面向?qū)ο?/b>
Python從設(shè)計之初就已經(jīng)是一門面向?qū)ο蟮恼Z言,正因?yàn)槿绱?,在Python中創(chuàng)建一個類和對象是很容易的。下面將詳細(xì)介紹Python的面向?qū)ο缶幊獭?/p>
如果你以前沒有接觸過面向?qū)ο蟮木幊陶Z言,那你可能需要先了解一些面向?qū)ο笳Z言的一些基本特征,在頭腦里頭形成一個基本的面向?qū)ο蟮母拍睿@樣有助于你更容易的學(xué)習(xí)Python的面向?qū)ο缶幊獭?/p>
接下來我們先來簡單的了解下面向?qū)ο蟮囊恍┗咎卣鳌?/p>
面向?qū)ο蠹夹g(shù)簡介
類(Class):用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實(shí)例。
類變量:類變量在整個實(shí)例化的對象中是公用的。類變量定義在類中且在函數(shù)體之外。類變量通常不作為實(shí)例變量使用。
數(shù)據(jù)成員:類變量或者實(shí)例變量用于處理類及其實(shí)例對象的相關(guān)的數(shù)據(jù)。
方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對其進(jìn)行改寫,這個過程叫方法的覆蓋(override),也稱為方法的重寫。
實(shí)例變量:定義在方法中的變量,只作用于當(dāng)前實(shí)例的類。
繼承:即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作為一個基類對象對待。例如,有這樣一個設(shè)計:一個Dog類型的對象派生自Animal類,這是模擬"是一個(is-a)"關(guān)系(例圖,Dog是一個Animal)。
實(shí)例化:創(chuàng)建一個類的實(shí)例,類的具體對象。
方法:類中定義的函數(shù)。
對象:通過類定義的數(shù)據(jù)結(jié)構(gòu)實(shí)例。對象包括兩個數(shù)據(jù)成員(類變量和實(shí)例變量)和方法。
和其它編程語言相比,Python在盡可能不增加新的語法和語義的情況下加入了類機(jī)制。
Python中的類提供了面向?qū)ο缶幊痰乃谢竟δ埽侯惖睦^承機(jī)制允許多個基類,派生類可以覆蓋基類中的任何方法,方法中可以調(diào)用基類中的同名方法。
對象可以包含任意數(shù)量和類型的數(shù)據(jù)。
類定義
語法格式如下:
Class類名稱:
Pass
類的組成:類名稱、屬性、方法
類實(shí)例化后,可以使用其屬性,實(shí)際上,創(chuàng)建一個類之后,可以通過類名稱訪問其屬性。
類對象
類的對象支持兩種操作:屬性引用和實(shí)例化。
屬性引用使用和Python中所有的屬性引用一樣的標(biāo)準(zhǔn)語法:obj.name。
類的對象創(chuàng)建后,類命名空間中所有的命名都是有效屬性名。U = User
創(chuàng)建對象的過程:
首先,用創(chuàng)建的類型的__new__()函數(shù)創(chuàng)建對象
其次,調(diào)用__init__()函數(shù)初始化對象的數(shù)據(jù)
Self關(guān)鍵字
self代表對象本身,可以是任意變量,則必須放在第一個參數(shù)位,但是規(guī)范要求必須使用self。
類的方法與普通的函數(shù)只有一個特別的區(qū)別——它們必須有一個額外的第一個參數(shù)名稱,按照慣例它的名稱是self。
類的方法
在類的內(nèi)部,用def來定義一個方法,與一般函數(shù)定義不同,類方法必須包含參數(shù)self,且為第一個參數(shù),self代表的是類的實(shí)例。
面向?qū)ο蟮奶卣鳌庋b
封裝?將對象敏感的數(shù)據(jù)封裝在類的內(nèi)部,不讓外界直接訪問,而是通過當(dāng)前類提供的set/get方法間接訪問數(shù)據(jù),此時就可以在set/get中添加限制條件進(jìn)行訪問數(shù)據(jù)的控制。
封裝實(shí)現(xiàn)的步驟:
定義類型,封裝零散數(shù)據(jù)【抽象的屬性】
[使用__slots__屬性,限制當(dāng)前類的屬性列表?為了代碼的統(tǒng)一性]
所有屬性私有化【屬性使用雙下劃線開頭,外界就不能直接訪問這樣的屬性了】
給每個屬性提供set/get方法,在方法中添加限制條件
高級封裝
使用@property和@get_method.setter注解,來注釋set/get方法,隱藏set/get方法的實(shí)現(xiàn),讓方法的使用方式和屬性一致
偽方法重載:python中,默認(rèn)不提供方法重載,但是在高級封裝的過程中,又出現(xiàn)了類似方法重載的代碼語法,所以~稱之為偽方法重載。
對方法的封裝
在封裝的過程中,除了封裝私有屬性,還可以針對一些底層的操作方法進(jìn)行私有化,將方法封裝在類的內(nèi)部,通過提供的一個公共方法來控制該方法的訪問權(quán)限
再說各種變量
全局變量:程序中任何位置都可以訪問的數(shù)據(jù);聲明在類的外部
變量/類屬性:當(dāng)前類創(chuàng)建的各種對象,可以共享的數(shù)據(jù);聲明在類的內(nèi)部,方法的外部
員變量/成員屬性:【創(chuàng)建的指定對象的特征】被對象所私有,對象之間不能使用對方的數(shù)據(jù)
局部變量:聲明在對象的方法或者函數(shù)中,函數(shù)中有效,出了函數(shù)無效【變量銷毀】
面向?qū)ο蟮奶卣鳌^承
繼承?一個類型繼承另一個類型,當(dāng)前類型就會擁有另一個類型的公共的屬性和方法,達(dá)到代碼的重復(fù)使用的目的。
繼承的語法:
class類型(被繼承的類型):
pass
繼承中出現(xiàn)的術(shù)語:
父類:被繼承的類,也稱為基類、超類
子類:當(dāng)前類,也稱為派生類
子類繼承父類,體現(xiàn)的時A is a B的關(guān)系
子類繼承父類,就可以使用父類中所有的公開的屬性和方法
繼承鏈
A繼承B,B繼承C,C繼承D
接繼承了B,間接繼承了C,D;此時A創(chuàng)建的對象,可以同時使用B,C,D所有公開的屬性和方法
那么問題又來了,多繼承呢?
·是否可以繼承多個類
·如果繼承的多個類每個類中都定了相同的函數(shù),那么那一個會被使用呢?
1、Python的類可以繼承多個類,Java和C#中則只能繼承一個類
2、Python的類如果繼承了多個類,那么其尋找方法的方式有兩種,分別是:
深度優(yōu)先和廣度優(yōu)先

·當(dāng)類是經(jīng)典類時,多繼承情況下,會按照深度優(yōu)先方式查找
·當(dāng)類是新式類時,多繼承情況下,會按照廣度優(yōu)先方式查找
經(jīng)典類和新式類,從字面上可以看出一個老一個新,新的必然包含了跟多的功能,也是之后推薦的寫法,從寫法上區(qū)分的話,如果當(dāng)前類或者父類繼承了object類,那么該類便是新式類,否則便是經(jīng)典類。


經(jīng)典類:首先去A類中查找,如果A類中沒有,則繼續(xù)去B類中找,如果B類中么有,則繼續(xù)去D類中找,如果D類中么有,則繼續(xù)去C類中找,如果還是未找到,則報錯
新式類:首先去A類中查找,如果A類中沒有,則繼續(xù)去B類中找,如果B類中么有,則繼續(xù)去C類中找,如果C類中么有,則繼續(xù)去D類中找,如果還是未找到,則報錯
注意:在上述查找過程中,一旦找到,則尋找過程立即中斷,便不會再繼續(xù)找了
python中,一個類型,可以同時繼承多個類型,同時擁有所有繼承類型的所有公開的屬性和方法
備注:在進(jìn)行代碼設(shè)計的過程中,可能會出現(xiàn)多繼承,所以盡量不要在父類中定義相同名稱的屬性或者方法
備注2:如果父類中出現(xiàn)了相同名稱的屬性和方法,在使用的時候子類調(diào)用時會優(yōu)先繼承優(yōu)先調(diào)用。
方法重寫:
類在自己類中重新定義父類中已經(jīng)存在的方法,在執(zhí)行該方法時,如果子類中沒有重寫就直接調(diào)用父類的方法,如果子類重寫了該方法,就直接調(diào)用子類重寫的方法!
擴(kuò)展:子類中,訪問父類的屬性和方法:
class User(Person):
def __init__(self, name, age):
#直接通過父類的類名稱調(diào)用父類的屬性和方法
Person.__init__(name, age)
#通過super()來調(diào)用父類的屬性和方法
super().__init__(name, age)
面向?qū)ο蟮奶卣鳎憾鄳B(tài)
程序在運(yùn)行的過程中,根據(jù)傳遞的參數(shù)的不同,執(zhí)行不同的函數(shù)或者操作不同的代碼,這種在運(yùn)行過程中才確定調(diào)用的方式成為運(yùn)行時多態(tài)
態(tài)即多種形態(tài),在運(yùn)行時確定其狀態(tài),在編譯階段無法確定其類型,這就是多態(tài)。Python中的多態(tài)和Java以及C++中的多態(tài)有點(diǎn)不同,Python中的變量是弱類型的,在定義時不用指明其類型,它會根據(jù)需要在運(yùn)行時確定變量的類型(個人覺得這也是多態(tài)的一種體現(xiàn)),并且Python本身是一種解釋性語言,不進(jìn)行預(yù)編譯,因此它就只在運(yùn)行時確定其狀態(tài),故也有人說Python是一種多態(tài)語言。在Python中很多地方都可以體現(xiàn)多態(tài)的特性,比如內(nèi)置函數(shù)len(object),len函數(shù)不僅可以計算字符串的長度,還可以計算列表、元組等對象中的數(shù)據(jù)個數(shù),這里在運(yùn)行時通過參數(shù)類型確定其具體的計算過程,正是多態(tài)的一種體現(xiàn)。
Python以它這種獨(dú)有的方式體現(xiàn)多態(tài)的根本原因我覺得有兩點(diǎn):
1)Python是解釋性語言;
2)Python中變量是弱類型的。