人工智能入門與實(shí)戰(zhàn)第一季:python基礎(chǔ)語法
什么是面向?qū)ο缶幊?/h4>
面向?qū)ο缶幊唐伺樱⑽腛bject-oriented programming卷雕,縮寫:OOP,是一種編程方式闰渔,在程序的開發(fā)過程根據(jù)實(shí)際問題抽象出一個(gè)個(gè)的對(duì)象暮现,然后把對(duì)象的方法和屬性封裝其中还绘,最后以提高軟件的復(fù)用性、靈活性和擴(kuò)展性栖袋。
目前主流的編程語言基本都是面向?qū)ο蟮木幊陶Z言拍顷,例如python、java栋荸、JavaScript菇怀、object-c、php晌块,等等爱沟。
當(dāng)然編程語言并非一開始就有面向?qū)ο蟮木幊谭绞剑热缥覀兪煜さ腸語言就是面向過程的語言匆背,隨著編程技術(shù)的發(fā)展呼伸,才逐漸出現(xiàn)面向?qū)ο蟮木幊谭绞剑驗(yàn)樗咏谖覀內(nèi)说乃季S方式钝尸,更容易被我們理解括享,所以它是更高級(jí)的編程語言。
除了上述說的兩種編程方式珍促,還有我們熟知的函數(shù)式編程铃辖、響應(yīng)式編程、面向切面編程等等編程方式猪叙,這些編程方式并非是對(duì)立的娇斩,他們的出現(xiàn)都是為了更好、更方便的開發(fā)程序穴翩,所以當(dāng)你在一個(gè)程序中同時(shí)發(fā)現(xiàn)有多種編程方式的時(shí)候并不要覺得奇怪犬第。
當(dāng)然面向?qū)ο蠛兔嫦蜻^程是最基本和最常用的編程方式,接下來我會(huì)用一個(gè)例子來說明面向過程和面向?qū)ο蟮膮^(qū)別芒帕,舉的例子并不能完全體現(xiàn)出兩者的區(qū)別歉嗓,只是讓你有一個(gè)直觀的感受。
案例:我家有一只貓和一只狗背蟆,貓的名字叫貓咪鉴分,1歲哮幢,狗的名字叫狗狗,2歲冠场,貓咪‘喵喵叫’家浇,狗狗‘旺旺叫’
要求使用python把貓咪和狗狗的信息存儲(chǔ)并打印,然后給狗狗換個(gè)名字碴裙,最后讓貓咪叫一聲,讓狗狗叫一聲点额。
1舔株、使用面向過程的編程方式實(shí)現(xiàn):
# 先分析要實(shí)現(xiàn)哪些功能,然后一步一步實(shí)現(xiàn)
# 1 存儲(chǔ)
cat_dic = {'name' : '貓咪', 'age' : 1}
print(cat_dic)
dog_dic = {'name' : '狗狗', 'age' : 2}
print(dog_dic)
# 2 給狗狗換個(gè)名字
dog_dic['name'] = '二哈'
print(dog_dic)
# 3 讓貓咪和狗狗叫
print('%s 喵喵喵...' % cat_dic['name'])
print('%s 旺旺旺...' % dog_dic['name'])
輸出結(jié)果:
{'name': '貓咪', 'age': 1}
{'name': '狗狗', 'age': 2}
{'name': '二哈', 'age': 2}
貓咪 喵喵喵...
二哈 旺旺旺...
2还棱、使用面向?qū)ο蟮木幊谭绞綄?shí)現(xiàn):
先分析整個(gè)程序中有哪些對(duì)象參與:貓载慈、狗
# 1 創(chuàng)建貓和狗的類(模板)
class Cat:
def __init__(self, name, age):
self.name = name # 定義屬性
self.age = age
def introduction(self): # 定義方法
print('%s %d歲' % (cat1.name, cat1.age))
def say(self): # 定義方法
print('喵喵喵...')
class Dog:
def __init__(self, name, age):
self.name = name # 定義屬性
self.age = age
def introduction(self): # 定義方法
print('%s %d歲' % (dog1.name, dog1.age))
def say(self): # 定義方法
print('旺旺旺...')
根據(jù)定義好的類創(chuàng)建對(duì)象,并使用對(duì)象調(diào)用方法
# 2 根據(jù)類(模板)來創(chuàng)建對(duì)象
cat1 = Cat('貓咪', 1)
dog1 = Dog('狗狗', 2)
# 3 貓咪自我介紹珍手、狗狗自我介紹
cat1.introduction()
dog1.introduction()
# 4 修改狗狗的名字
dog1.name = '二哈'
dog1.introduction()
# 5 喵咪叫办铡、狗狗叫
cat1.say()
dog1.say()
輸出結(jié)果:
貓咪 1歲
狗狗 2歲
二哈 2歲
喵喵喵...
旺旺旺...
對(duì)比以上兩種實(shí)現(xiàn)方式,我們先不討論他們的擴(kuò)展性琳要、復(fù)用性寡具、安全性,直觀感覺上我們會(huì)覺得第二種編程方式更符合我們?nèi)祟惖乃伎挤绞街刹梗菀妆晃覀兝斫狻?/p>
好了童叠,以上把面向過程編程和面向?qū)ο缶幊痰姆绞阶隽艘粋€(gè)對(duì)比,我們先從直觀上感受课幕,接下來我們會(huì)詳細(xì)講解面向?qū)ο缶幊痰膬?nèi)容厦坛。
類的定義
我們先來搞清楚什么是類?什么是對(duì)象乍惊?
我們?cè)谏厦嬉呀?jīng)創(chuàng)建了2個(gè)類杜秸,一個(gè)是Cat類,一個(gè)是Dog類润绎,我們還說了類就是模板撬碟,可以通過類(模板)去創(chuàng)建具體的對(duì)象,那么我們上面通過Cat類創(chuàng)建了cat1這個(gè)對(duì)象(就是我家的貓咪)凡橱,通過Dog類創(chuàng)建了dog1這個(gè)對(duì)象(就是我家的狗狗)
類和對(duì)象的概念搞清楚了嗎小作?我說“人”,他是類稼钩,我說“路邊走的那個(gè)人”顾稀,他就是對(duì)象;我說“手機(jī)”坝撑,它也是類静秆,我說“我兜里的這個(gè)手機(jī)”它就是對(duì)象粮揉;所以類是一群具體事物的總稱,而對(duì)象則是類對(duì)應(yīng)的具體的個(gè)體抚笔。
一個(gè)類包含屬性和方法扶认,我們上面的例子中貓的名字name和年齡age就是屬性,說話say就是方法(行為)殊橙。
定義類的語法格式:
class 類名:
類體
定義類的說明:
- 我們?cè)谇懊嬷v過標(biāo)識(shí)符的命名規(guī)則辐宾,類名首字母大寫,包含多個(gè)英文單詞時(shí)單詞首字母大寫膨蛮。
- 類體中定義屬性和方法
- init()是構(gòu)造方法叠纹,用來初始化對(duì)象的屬性,默認(rèn)的第一個(gè)參數(shù)是self敞葛,它代表對(duì)象本身
例如我們上面定義的Cat類:
class Cat:
def __init__(self, name, age):
self.name = name # 實(shí)例屬性
self.age = age
def introduction(self): # 實(shí)例方法
print('%s %d歲' % (cat1.name, cat1.age))
def say(self): # 實(shí)例方法
print('喵喵喵...')
使用類(模板)創(chuàng)建對(duì)象:
cat1 = Cat('貓咪', 1)
使用”類名([參數(shù)列表])”默認(rèn)會(huì)調(diào)用init方法誉察,給name、age賦值惹谐。
實(shí)例屬性和實(shí)例方法
我們上面說了類體中包含屬性和方法持偏,怎么又來了一個(gè)實(shí)例屬性和實(shí)例方法?這就說明類中的屬性和方法是有不同類型的氨肌。
實(shí)例屬性
實(shí)例屬性可以理解為對(duì)象屬性鸿秆,他是屬于每個(gè)創(chuàng)建的對(duì)象的,一般是定義在init方法中的儒飒,上面我們定義的Cat類中的name谬莹、age都是實(shí)例屬性。
我們可以通過“對(duì)象.屬性名”訪問實(shí)例屬性桩了,例如cat1.name
實(shí)例方法
實(shí)例方法是對(duì)象的方法附帽,語法格式:
def 方法名(self [,參數(shù)列表])
方法體
實(shí)例方法調(diào)用格式:對(duì)象.方法名([參數(shù)列表])
實(shí)例方法的第一個(gè)參數(shù)必須是self,之后的參數(shù)可以自行定義井誉,調(diào)用方法時(shí)蕉扮,第一個(gè)參數(shù)self無需手動(dòng)傳入,它由系統(tǒng)自動(dòng)傳入颗圣。
舉例:
# 定義Cat類
class Cat:
def __init__(self, name, age):
self.name = name # 實(shí)例屬性
self.age = age
def introduction(self): # 實(shí)例方法
print('%s %d歲' % (cat1.name, cat1.age))
def say(self): # 實(shí)例方法
print('喵喵喵...')
# 通過類創(chuàng)建對(duì)象(創(chuàng)建一只貓)
cat1 = Cat('貓咪', 1)
# 通過對(duì)象訪問實(shí)例屬性
print(cat1.name)
# 通過對(duì)象調(diào)用實(shí)例方法
cat1.say()
類屬性和類方法
上面講了實(shí)例屬性和實(shí)例方法喳钟,他們都是屬于對(duì)象的,類屬性和類方法則是屬于類的在岂,可以被所有對(duì)象共享奔则,我們來看他們的區(qū)別
類屬性
定義在init之外的屬性,類屬性使用的頻率非常低蔽午,使用更多的還是實(shí)例屬性易茬。
我們可以通過“類名.屬性名”訪問類屬性
類方法
類方法通過裝飾器@classmethod來定義,語法格式:
@classmethod
def 類方法(cls [,參數(shù)列表])
函數(shù)體
類方法調(diào)用格式:
類名.類方法名([參數(shù)列表])
類方法的使用說明:
- 第一個(gè)參數(shù)必須是cls,之后的參數(shù)可以自行定義抽莱,調(diào)用方法時(shí)范抓,第一個(gè)參數(shù)cls無需手動(dòng)傳入,它由系統(tǒng)自動(dòng)傳入食铐。
- 類方法中不能訪問實(shí)例屬性和實(shí)例方法
靜態(tài)方法
在類中使用裝飾器@staticmethod修飾的方法匕垫,稱為靜態(tài)方法,它和我們之前學(xué)習(xí)的函數(shù)沒有太大區(qū)別虐呻,它僅僅托管于某個(gè)類的名稱空間中象泵,便于使用和維護(hù)。
靜態(tài)方法定義格式:
@staticmethod
def 類方法(參數(shù)列表)
函數(shù)體
靜態(tài)方法的調(diào)用:類名.靜態(tài)方法铃慷、對(duì)象.靜態(tài)方法
舉例:
class Cat:
# 類屬性
count = 0
# 實(shí)例方法
def __init__(self, name, age):
# 實(shí)例屬性
self.name = name
# 實(shí)例屬性
self.age = age
# 每次創(chuàng)建一只貓单芜,計(jì)數(shù)加1
Cat.count = Cat.count + 1
# 實(shí)例方法
def say(self):
print('喵喵喵...')
# 類方法
@classmethod
def print_count(cls):
# 使用類名訪問類屬性
print('一共創(chuàng)建%d只貓' % Cat.count)
# 類方法中不能訪問實(shí)例屬性和實(shí)例方法
# 定義靜態(tài)方法
@staticmethod
def help():
print('這里是貓類,你可以創(chuàng)建一只小貓和你玩兒')
cat2 = Cat('mimi' , 3)
# 使用類名調(diào)用類方法
Cat.print_count()
# 使用對(duì)象調(diào)用靜態(tài)方法
cat2.help()
# 使用類名調(diào)用靜態(tài)方法
Cat.help()
輸出結(jié)果:
一共創(chuàng)建1只貓
這里是貓類犁柜,你可以創(chuàng)建一只小貓和你玩兒
這里是貓類,你可以創(chuàng)建一只小貓和你玩兒
關(guān)于實(shí)例屬性堂淡、實(shí)例方法和類屬性馋缅、類方法的區(qū)別,可以簡(jiǎn)單這樣來記:前者屬于對(duì)象绢淀,可以使用對(duì)象來訪問萤悴,后者屬于類,可以使用類來訪問皆的。
私有屬性和私有方法
我們知道定義類的時(shí)候覆履,類體包含屬性和方法,python中默認(rèn)的屬性和方法费薄,外部都是可以訪問的硝全,當(dāng)然我們也可以將屬性和方法設(shè)置成私有的,以限制外部的訪問楞抡。
就像你去餐館吃飯伟众,我們只可以取做好的飯菜,但是餐館內(nèi)的食材我們是觸及不到的召廷,以保證食物的安全性凳厢。幾乎所有面向?qū)ο蟮木幊陶Z言都對(duì)屬性和方法設(shè)置了訪問權(quán)限,以保證程序的安全性竞慢。
python中如何設(shè)置私有屬性和私有方法呢先紫?
1、屬性和方法名前以兩條下劃線__開始的為私有屬性和私有方法
2筹煮、在類的內(nèi)部可以直接訪問私有屬性和私有方法
3遮精、在類外部原則上是不可以訪問私有屬性和私有方法(python沒有嚴(yán)格意義上的不可訪問,這點(diǎn)和其他語言并不一樣)
舉例:
class Cat:
def __init__(self, name, age):
self.name = name
# 私有屬性
self.__age = age
def say(self):
# 類內(nèi)部可以訪問私有屬性
print('%s %d歲 喵喵喵...' % (self.name, self.__age))
# 私有方法
def __hello(self):
print('hello...')
cat3 = Cat('tom', 1)
cat3.say()
# 類外部正常情況下無法訪問私有屬性和私有方法
# print(cat3.__age)
# cat3.__hello()
# 可以通過類名來強(qiáng)制訪問私有屬性(一般我們不這樣做)
print(cat3._Cat__age)
cat3._Cat__hello()
輸出結(jié)果:
tom 1歲 喵喵喵...
1
hello...
面向?qū)ο笕筇匦裕悍庋b寺谤、繼承仑鸥、多態(tài)
封裝
比如我們定義的Cat類吮播,有一個(gè)say方法,對(duì)于外部的使用者來說并不知道內(nèi)部是怎么實(shí)現(xiàn)的眼俊,需要的時(shí)候調(diào)用即可意狠。
再比如我們講到的私有屬性和私有方法,保證了程序的安全性疮胖,這些都是面向?qū)ο蠓庋b性的體現(xiàn)环戈。
繼承
還記得本章開始我們定義了兩個(gè)類,一個(gè)Cat類澎灸,一個(gè)Dog類院塞,我們現(xiàn)在回過頭來看會(huì)發(fā)現(xiàn)他們的屬性和方法都一樣,都有name和age屬性性昭,都有say方法拦止,這些重復(fù)相同的代碼顯然違背了程序設(shè)計(jì)的理念:代碼的復(fù)用性,那么通過繼承可以完美的解決這個(gè)問題糜颠。
貓和狗都是動(dòng)物汹族,所以我們可以抽象出一個(gè)Animal類,動(dòng)物也有名字和年齡其兴,也都會(huì)發(fā)出聲音顶瞒,所以我們可以這樣寫:
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print('%s 叫...' % self.name)
接下來我們創(chuàng)建Cat類和Dog類,但這次不同的是他們都要繼承Animal:
# 注意繼承的語法格式
class Cat(Animal):
# 使用pass表示不做任何事元旬,以后可以在此繼續(xù)添加代碼
pass
class Dog(Animal):
pass
cat4 = Cat('tom', 1)
cat4.say()
dog4 = Dog('jerry', 2)
dog4.say()
輸出結(jié)果:
tom 叫...
jerry 叫...
可以看到Cat類和Dog類沒有寫任何額外代碼榴徐,只是繼承了Animal,就擁有了Animal的所有屬性和方法匀归,這就是繼承的魅力坑资。
如果父類中的屬性和方法無法滿足子類,可以在子類中添加額外的屬性和方法:
class Dog(Animal):
def __init__(self, name, age, hair_color):
# 新增毛發(fā)顏色屬性
self.hair_color = hair_color
self.name = name
self.age = age
# 也可以調(diào)用父類的__init__方法對(duì)name和age賦值
# Animal.__init__(self, name, age)
# 新增跑的方法
def run(self):
print('%s 跑...' % self.name)
dog4 = Dog('jerry', 2, 'yellow')
dog4.run()
輸出結(jié)果:
jerry 跑...
重寫父類方法
為什么要重寫父類的方法朋譬?原因很簡(jiǎn)單就是父類的方法無法滿足子類時(shí)盐茎,比如我們發(fā)現(xiàn)Animal類中的say方法并不能滿足Dog類(狗有狗的叫法),重寫父類的方法之后徙赢,再調(diào)用時(shí)就會(huì)調(diào)用子類的方法了字柠。
class Dog(Animal):
# 重寫父類的say方法,重寫英文名叫override
def say(self):
print('旺旺旺...')
dog4 = Dog('jerry', 2)
dog4.say()
輸出結(jié)果:
旺旺旺...
我們現(xiàn)在來總結(jié)一下繼承相關(guān)特點(diǎn):
1狡赐、被繼承的類被稱為父類或超類窑业,例如Animal就是Cat類和Dog類的父類
2、繼承之后的類稱為子類枕屉,例如Cat類和Dog類
3常柄、繼承的語法格式:(python中支持多重繼承,即子類可以繼承多個(gè)父類)
class 子類類名(父類1[, 父類2, ...]):
類體
4、在子類中可以添加新的屬性和方法
5西潘、在子類中可以重寫父類中的方法
多態(tài)
多態(tài)這個(gè)概念并不太好解釋卷玉,我還是拿Animal類來嘗試著舉例:
我們知道動(dòng)物幾乎都有叫聲,貓有貓的叫聲喷市,狗有狗的叫聲相种,我們?nèi)祟愐灿凶约旱膮群奥暎瑢?duì)于同一類的同一個(gè)行為所表現(xiàn)出的多種狀態(tài)我們稱之為多態(tài)品姓。
多態(tài)對(duì)于程序的靈活性寝并、擴(kuò)展性方面起到了非常好的作用,我們看它是怎么做到的腹备?
1衬潦、先創(chuàng)建Animal類
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print('動(dòng)物叫...')
2、創(chuàng)建一個(gè)貓類植酥,重寫父類的say方法
class Cat(Animal):
def say(self):
print('喵喵喵...')
3镀岛、創(chuàng)建一個(gè)狗類,重寫父類的say方法
class Dog(Animal):
def say(self):
print('旺旺旺...')
4友驮、創(chuàng)建一個(gè)人類哎媚,重寫父類的say方法(人類也是動(dòng)物,也可以繼承Animal類)
class Person(Animal):
def say(self):
print('吃了嗎您喊儡?')
5、定義一個(gè)函數(shù)稻据,要求每個(gè)動(dòng)物都給大家打聲招呼
def animal_say(animal):
# 這里要做容錯(cuò)處理艾猜,萬一傳進(jìn)來的不是動(dòng)物類就報(bào)錯(cuò)了
if isinstance(animal, Animal):
animal.say()
else:
print('參數(shù)異常!請(qǐng)傳入動(dòng)物類型的數(shù)據(jù)捻悯!')
6匆赃、調(diào)用animal_say函數(shù),傳入不同的動(dòng)物今缚,打聲招呼
cat5 = Cat('tom', 1)
dog5 = Dog('jerry', 2)
p1 = Person('李大爺', 88)
animal_say(cat5)
animal_say(dog5)
animal_say(p1)
輸出結(jié)果:
喵喵喵...
旺旺旺...
吃了嗎您算柳?
我們發(fā)現(xiàn)傳入的都是動(dòng)物類型的數(shù)據(jù),他們?cè)趫?zhí)行同一個(gè)行為say方法是姓言,表現(xiàn)出了不同的形態(tài)(看打印的內(nèi)容)瞬项。
這其實(shí)也不難理解,因?yàn)槌绦驎?huì)識(shí)別傳進(jìn)來的具體是哪種動(dòng)物類型何荚,然后去調(diào)用他們自己的say方法囱淋,所以才表現(xiàn)出了不同的行為。
扯淡系列
...也許這是你給一家動(dòng)物園寫的一個(gè)讓動(dòng)物打招呼的程序餐塘,后來動(dòng)物園長(zhǎng)說我們又新來一批動(dòng)物妥衣,也要他們給大家打招呼...
...你淡定的跟園長(zhǎng)講,我早已預(yù)見你有這樣的需求了,沒關(guān)系税手,只要讓新來的動(dòng)物繼承Animal類蜂筹,重寫say方法...
...然后再把他們放進(jìn)animal_say方法里,無需修改animal_say方法芦倒,他們就會(huì)自動(dòng)給大家打招呼了...
...這時(shí)你心里暗自竊喜艺挪,幸好當(dāng)初自己使用了多態(tài)...
以上的例子你明白了嗎?這就是我們開始說的熙暴,多態(tài)的使用會(huì)增加程序的靈活性和擴(kuò)展性闺属,這也是面向?qū)ο蟮奶匦灾弧?/p>
本章對(duì)應(yīng)的源碼文件:se1_ch8_OOP.py
本章作業(yè)
1、編寫一個(gè)飛機(jī)類周霉,飛機(jī)有顏色掂器、名稱、時(shí)速等屬性俱箱,有飛行的方法国瓮。
2、編寫一個(gè)戰(zhàn)斗機(jī)類狞谱,除了有題目1中的屬性和方法外乃摹,同時(shí)戰(zhàn)斗機(jī)有作戰(zhàn)高度、有射擊的方法跟衅。
本章總結(jié)
學(xué)完本章之后孵睬,有幾個(gè)概念你一定要掌握,什么是類伶跷?什么是對(duì)象掰读?什么是對(duì)象的屬性和方法?什么是類屬性和類方法叭莫?除了概念之外蹈集,你還要會(huì)創(chuàng)建類,通過類創(chuàng)建對(duì)象雇初,以及調(diào)用對(duì)象的屬性和方法拢肆。
本章就到這里,我是豬弟爸爸靖诗,這里我會(huì)持續(xù)更新人工智能自學(xué)內(nèi)容郭怪,有問題請(qǐng)關(guān)注我的公眾號(hào)zhudipapa,我會(huì)統(tǒng)一在公眾號(hào)下方回復(fù)呻畸,我們下節(jié)見移盆。