面向?qū)ο缶幊趟枷氲陌l(fā)展歷程
面向?qū)ο?Object Oriented):是一種編程思想绒北,是一種對現(xiàn)實(shí)世界的理解和抽閑的方法黎侈,已經(jīng)從程序設(shè)計(jì)開發(fā),擴(kuò)展到了數(shù)據(jù)庫系統(tǒng)闷游、交互式界面峻汉、應(yīng)用結(jié)構(gòu)、應(yīng)用平臺脐往、分布式系統(tǒng)休吠、網(wǎng)絡(luò)管理、人工智能等等各個(gè)應(yīng)用方向业簿。
面向?qū)ο蟪霈F(xiàn)以前瘤礁,結(jié)構(gòu)化程序設(shè)計(jì)是程序設(shè)計(jì)的主流,結(jié)構(gòu)化程序設(shè)計(jì)又稱為面向過程的程序設(shè)計(jì)梅尤。在面向過程程序設(shè)計(jì)中柜思,問題被看作一系列需要完成的任務(wù)岩调,函數(shù)(在此泛指例程、函數(shù)赡盘、過程)用于完成這些任務(wù)誊辉,解決問題的焦點(diǎn)集中于函數(shù)。其中函數(shù)是面向過程的亡脑,即它關(guān)注如何根據(jù)規(guī)定的條件完成指定的任務(wù)。在多函數(shù)程序中邀跃,許多重要的數(shù)據(jù)被放置在全局?jǐn)?shù)據(jù)區(qū)霉咨,這樣它們可以被所有的函數(shù)訪問。每個(gè)函數(shù)都可以具有它們自己的局部數(shù)據(jù)拍屑。
但這種結(jié)構(gòu)很容易造成全局?jǐn)?shù)據(jù)在無意中被其他函數(shù)改動(dòng)途戒,因而程序的正確性不易保證。面向?qū)ο蟪绦蛟O(shè)計(jì)的出發(fā)點(diǎn)之一就是彌補(bǔ)面向過程程序設(shè)計(jì)中的一些缺點(diǎn):對象是程序的基本元素僵驰,它將數(shù)據(jù)和操作緊密地連結(jié)在一起喷斋,并保護(hù)數(shù)據(jù)不會(huì)被外界的函數(shù)意外地改變。
面向?qū)ο笤O(shè)計(jì)方法以對象為基礎(chǔ)蒜茴,利用特定的軟件工具直接完成從對象客體的描述到軟件結(jié)構(gòu)之間的轉(zhuǎn)換星爪。這是面向?qū)ο笤O(shè)計(jì)方法最主要的特點(diǎn)和成就。面向?qū)ο笤O(shè)計(jì)方法的應(yīng)用解決了傳統(tǒng)結(jié)構(gòu)化開發(fā)方法中客觀世界描述工具與軟件結(jié)構(gòu)的不一致性問題粉私,縮短了開發(fā)周期顽腾,解決了從分析和設(shè)計(jì)到軟件模塊結(jié)構(gòu)之間多次轉(zhuǎn)換映射的繁雜過程,是一種很有發(fā)展前途的系統(tǒng)開發(fā)方法诺核。
最典型的動(dòng)態(tài)語言有JavaScript, Python, Ruby等等抄肖。它們一個(gè)重大的變化就是將類的信息改變?yōu)閯?dòng)態(tài)的,并提出了Ducking Type的概念窖杀。這在很大程度上提升了編程的生產(chǎn)力漓摩。
封裝的意義和操作過程
封裝?將對象敏感的數(shù)據(jù)封裝在類的內(nèi)部入客,不讓外界直接訪問管毙,而是通過當(dāng)前類提供的set/get方法間接訪問數(shù)據(jù),此時(shí)就可以在set/get中添加限制條件進(jìn)行訪問數(shù)據(jù)的控制痊项。
封裝實(shí)現(xiàn)的步驟:
定義類型锅风,封裝零散數(shù)據(jù)【抽象的屬性】
[使用__slots__屬性,限制當(dāng)前類的屬性列表->為了代碼的統(tǒng)一性]
所有屬性私有化【屬性使用雙下劃綫開頭鞍泉,外界就不能直接訪問這樣的屬性了】
給每個(gè)屬性提供set/get方法皱埠,在方法中添加限制條件
高級封裝
使用@property和@get_method.setter注解,來注釋set/get方法咖驮,隱藏set/get方法的實(shí)現(xiàn)边器,讓方法的使用方式和屬性一致
偽方法重載:python中训枢,默認(rèn)不提供方法重載,但是在高級封裝的過程中忘巧,又出現(xiàn)了類似方法重載的代碼語法恒界,所以~稱之為偽方法重載。
對方法的封裝
在封裝的過程中砚嘴,除了封裝私有屬性十酣,還可以針對一些底層的操作方法進(jìn)行私有化,將方法封裝在類的內(nèi)部际长,通過提供的一個(gè)公共方法來控制該方法的訪問權(quán)限
再說各種變量
全局變量:程序中任何位置都可以訪問的數(shù)據(jù)耸采;聲明在類的外部
類變量/類屬性:當(dāng)前類創(chuàng)建的各種對象,可以共享的數(shù)據(jù)工育;聲明在類的內(nèi)部虾宇,方法的外部
成員變量/成員屬性:【創(chuàng)建的指定對象的特征】被對象所私有,對象之間不能使用對方的數(shù)據(jù)
局部變量:聲明在對象的方法或者函數(shù)中如绸,函數(shù)中有效嘱朽,出了函數(shù)無效【變量銷毀】
繼承的意義和操作過程
一個(gè)類型繼承另一個(gè)類型,當(dāng)前類型就會(huì)擁有另一個(gè)類型的公共的屬性和方法怔接,達(dá)到代碼的重復(fù)使用的目的搪泳。
繼承是讓我們抽象的對象之間存在一定的所屬關(guān)系
在繼承關(guān)系中,我們一定要明確會(huì)出現(xiàn)這樣的一種關(guān)系~父類扼脐、子類森书,子類繼承自父類柒竞,可以繼承父類中的公開的屬性和方法(不能繼承私有的屬性或者方法)
python中所有的對象都是直接或者間接繼承自object對象的:
class Person(object):
pass
繼承的語法:
class 類型(被繼承的類型):
pass
繼承中出現(xiàn)的術(shù)語:
繼承是類型之間的關(guān)系:
繼承中锌钮,首先必須是兩個(gè)或者兩個(gè)以上的類型之間的關(guān)系坛缕,注意是類型之間的關(guān)系
父類:被繼承的類幸冻,也稱為基類陡鹃、超類
子類:當(dāng)前類常潮,也稱為派生類
子類繼承父類保礼,體現(xiàn)的時(shí)A is a B的關(guān)系
子類繼承父類镐依,就可以使用父類中所有的公開的屬性和方法
繼承鏈
A繼承B须喂,B繼承C吁断,C繼承D
A直接繼承了B,間接繼承了C,D坞生;此時(shí)A創(chuàng)建的對象仔役,可以同時(shí)使用B,C,D中所有公開的屬性和方法
多繼承
python中,一個(gè)類型是己,可以同時(shí)繼承多個(gè)類型又兵,同時(shí)擁有所有繼承類型的所有公開的屬性和方法
備注:在進(jìn)行代碼設(shè)計(jì)的過程中,可能會(huì)出現(xiàn)多繼承,所以盡量不要在父類中定義相同名稱的屬性或者方法
備注2:如果父類中出現(xiàn)了相同名稱的屬性和方法沛厨,在使用的時(shí)候子類調(diào)用時(shí)會(huì)優(yōu)先繼承優(yōu)先調(diào)用宙地。
在python的繼承機(jī)制中,私有的屬性是不允許被繼承和互相訪問的逆皮,子類不能繼承和訪問父類中私有的屬性和方法宅粥,父類同樣也不能訪問子類中私有的屬性和方法
子類只能繼承父類中公開的屬性和方法
子類中可以通過父類的名稱或者super()來訪問父類的屬性和方法
# 父類
class Person(object):
def __init__(self, name, age):
self.__name = name
self.__age = age
def play(self):
print(self.__name + "在玩游戲")
# 子類
class Man(Person):
def __init__(self, name, age):
# 通過父類名稱訪問父類中初始化的方法
Person.__init__(self, name,age)
# 子類
class Women(Person):
def __init__(self, name, age):
# 通過super()訪問父類初始化的方法
# super(Women, self).__init....super中的參數(shù)可以省略
super().__init__(self, name, age)
方法重寫:
子類在自己類中重新定義父類中已經(jīng)存在的方法,在執(zhí)行該方法時(shí)电谣,如果子類中沒有重寫就直接調(diào)用父類的方法秽梅,如果子類重寫了該方法,就直接調(diào)用子類重寫的方法剿牺!
# 父類
class Person(object):
def play(self):
print("Person中玩游戲的方法執(zhí)行了...")
# 子類
class Children(Person):
# 重寫父類中play方法
def play(self):
print("Children中玩游戲的方法執(zhí)行.....")
# 創(chuàng)建子類對象
c = Children()
c.play()
# 執(zhí)行結(jié)果
~Children中玩游戲的方法執(zhí)行.....
多態(tài)的意義和操作過程
程序在運(yùn)行的過程中风纠,根據(jù)傳遞的參數(shù)的不同,執(zhí)行不同的函數(shù)或者操作不同的代碼牢贸,這種在運(yùn)行過程中才確定調(diào)用的方式成為運(yùn)行時(shí)多態(tài)
方法重寫實(shí)現(xiàn)的運(yùn)行時(shí)多態(tài),對象在執(zhí)行具體的方法時(shí)镐捧,會(huì)直接執(zhí)行父類中繼承的對應(yīng)的方法潜索,如果該方法在子類中重寫了,就會(huì)執(zhí)行子類中重寫過的方法懂酱,實(shí)現(xiàn)的是一種運(yùn)行過程中的多態(tài)處理
多態(tài)實(shí)現(xiàn)代碼如下:
class Person:
def __init__(self, name, age, health):
self.name = name
self.age = age
self.health = health
# 治愈康復(fù)
def recure(self):
print("[%s]康復(fù)了,當(dāng)前健康值%s\n" % (self.name, self.health))
# 子類
class Man(Person):
def __init__(self, name, age, health):
Person.__init__(self, name, age, health)
def recure(self):
print("[%s]男的我終于康復(fù)了,當(dāng)前健康值%s\n" % (self.name, self.health))
class Woman(Person):
def __init__(self, name, age, health):
Person.__init__(self, name, age, health)
def recure(self):
print("[%s]女的我終于康復(fù)了,當(dāng)前健康值%s\n" % (self.name, self.health))
class Animal:
# name姓名 age年齡 health健康值【0~50極度虛弱,51~70亞健康,71~85健康竹习,86~100強(qiáng)壯】
def __init__(self, name, age, health):
self.name = name
self.age = age
self.health = health
# 康復(fù)的方法
def recure(self):
print("[%s]嘿嘿嘿,終于康復(fù)了列牺,當(dāng)前健康值%s\n" % (self.name, self.health))
# 醫(yī)院
class Hospital:
def __init__(self):
self.__name = "人民醫(yī)院"
# 醫(yī)院治療患者整陌,因此對象是一個(gè)人person
# 若不是人,則不治療并報(bào)出錯(cuò)誤
def care(self, person):
if isinstance(person, Person):
if (person.health > 0) and (person.health <= 50):
print("手術(shù)....")
person.health += 30
person.recure()
elif (person.health > 50) and (person.health < 75):
print("吃藥....")
person.health += 15
person.recure()
else:
print("沒有生病")
else:
print("不是人")
hospital = Hospital()
Pi = Person("Pi", 27, 40)
Mr_wang = Man("王老菊", 29, 51)
Mian = Woman("免免", 28, 49)
pig = Animal("小豬", 10, 88)
hospital.care(Mr_wang)
hospital.care(Pi)
hospital.care(Mian)
hospital.care(pig)
同時(shí)如果功能需要擴(kuò)展瞎领,需要多出來一個(gè)人物類型:小孩泌辫,小孩也會(huì)生病,也需要治療~此時(shí)對于功能的擴(kuò)展非常簡潔九默,值需要添加如下代碼就可以搞定:
# 創(chuàng)建一個(gè)小孩類型震放,繼承自Person
class Children(Person):
def __init__(self, name):
Person.__init__(self, name)
# 創(chuàng)建具體的小孩對象
c = Children("小家伙")
h.care(c) # 執(zhí)行結(jié)果~小家伙康復(fù)了
可以看到這里擴(kuò)展一個(gè)功能變得非常的簡單,對象和對象之間的協(xié)同關(guān)系由于繼承多態(tài)的存在讓功能的擴(kuò)展實(shí)現(xiàn)起來比較快捷了驼修。
通過isinstance()
函數(shù)進(jìn)行變量所屬數(shù)據(jù)類型的判斷
這樣只有Person類型才可以通過進(jìn)行care()
__slots__
殿遂,該屬性的值是一個(gè)元組,元組中定義了類中可以出現(xiàn)的所有成員屬性的名稱
元組中規(guī)范了可能出現(xiàn)在類的成員屬性列表乙各。
類在創(chuàng)建好對象之后墨礁,可以在對象上直接掛在屬性,這在一定程度上對于程序處理的靈活度有所提升耳峦,但是同樣的恩静,過于靈活的代碼都會(huì)極大的降低代碼的可讀性,所以python提供了slots這樣的類屬性進(jìn)行規(guī)范蹲坷,規(guī)范類屬性中只能出現(xiàn)的成員屬性的列表蜕企,防止惡意的擴(kuò)展咬荷。
__str__()
可以更改我們的類的對象的打印輸出結(jié)果
這個(gè)__str__()
方法是從object對象繼承而來的,我們這里只是對它進(jìn)行了方法重寫轻掩。
另外幸乒,在命令行操作過程中,如果不用print()方法打印而是直接輸入對象唇牧,會(huì)發(fā)現(xiàn)執(zhí)行的結(jié)果又是讓人晦澀難懂的東西了罕扎,在命令行直接使用對象調(diào)用的不是對象的__str__()
方法,而是__repr__()
方法丐重,只需要簡單的修改即可
__call__()
方法腔召,主要用于對象快捷執(zhí)行而存在的一個(gè)魔術(shù)方法,方便進(jìn)行對象中某些重要數(shù)據(jù)的初始化整理工作等扮惦。
多繼承時(shí)臀蛛,
當(dāng)前類繼承了一個(gè)或者多個(gè)父類,當(dāng)前類就同時(shí)繼承了父類中的公開的屬性和函數(shù)崖蜜,如果不同的父類中出現(xiàn)相同的屬性/函數(shù)浊仆,就需要明確執(zhí)行的過程
# 定義了一個(gè)基礎(chǔ)類
class Person(object):
def __init__(self):
self.name = "tom"
class Student(Person):
def eat(self):
print("吃食堂....")
def respect(self):
print("尊師重道")
class Son(Person):
def eat(self):
print("吃美食...")
def fealty(self):
print("尊老愛幼")
# User類型,繼承了兒子類型豫领、學(xué)生類型
# 同時(shí)擁有兒子類型和學(xué)生類型中所有的公共屬性和方法
class User(Son, Student):
pass
# 創(chuàng)建對象
u = User()
# u是學(xué)生角色
u.respect()
# u是兒子角色
u.fealty()
# 吃飯
# 如果繼承的多個(gè)父類中抡柿,出現(xiàn)了相同的屬性和方法,就會(huì)執(zhí)行方法或者屬性的搜索
# 過程等恐,搜索到對應(yīng)的屬性和方法洲劣,立即執(zhí)行,中斷搜索
# 屬性和方法的搜索過程课蔬,可以通過 類型.__mro__ 魔法屬性進(jìn)行查看
# 優(yōu)先繼承囱稽,優(yōu)先執(zhí)行
u.eat()
print(User.__mro__)# method from object
#運(yùn)行結(jié)果
~
尊師重道
尊老愛幼
吃美食...
(<class '__main__.User'>, <class '__main__.Son'>, <class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>)
一旦出現(xiàn)多重繼承,就會(huì)出現(xiàn)這樣繼承的多個(gè)父類中出現(xiàn)了多個(gè)相同名稱的變量或者方法的情況二跋,使用的這些變量和方法的時(shí)候一定要注意一個(gè)原則粗悯,先繼承誰就使用誰的變量或者方法!