python面向對象基礎

面向對象基礎

1. 簡述

  • 編程方式:

  • 面向過程: 根據代碼在腳本的堆疊順序,從上到下依次執行

  • 函數式編程:將相同功能的代碼封裝到函數中,直接調用即可,減少代碼重複性

  • 面向對象:對函數進行分類和封裝,將同類的函數放到一個類中,使調用更簡單

  • 爲嘛要面向對象

  • 應用需求 
    要的對系統的cpu、內存、硬盤等進行監控,超過閾值則告警

while True:    if cpu利用率 > 90%:        #發送郵件提醒        連接郵箱服務器        發送郵件        關閉連接    if 硬盤使用空間 > 90%:        #發送郵件提醒        連接郵箱服務器        發送郵件        關閉連接    if 內存佔用 > 80%:        #發送郵件提醒        連接郵箱服務器        發送郵件        關閉連接

隨着python的學習,開始使用函數式編程

def 發送郵件(內容)    #發送郵件提醒    連接郵箱服務器    發送郵件    關閉連接while True:    if cpu利用率 > 90%:        發送郵件('CPU報警')    if 硬盤使用空間 > 90%:        發送郵件('硬盤報警')    if 內存佔用 > 80%:        發送郵件('內存報警')

函數式編程增加了代碼的可讀性和重用性,但是,這僅僅是單臺機器的監控,如果我要監控多臺呢,可能需要需要這樣寫:

def 發送郵件(內容)    #發送郵件提醒    連接郵箱服務器    發送郵件    關閉連接while True:for host in host-list:  #通過遍歷host列表來進行監控    if cpu利用率 > 90%:        發送郵件('CPU報警')    if 硬盤使用空間 > 90%:        發送郵件('硬盤報警')    if 內存佔用 > 80%:        發送郵件('內存報警')

這樣貌似實現了,但是如果是1000臺機器呢,可能當循環到999臺的時候,第100臺已經出現問題了。造成告警延誤。而如果使用面向對象呢?將很好的解決此問題

class host:def 發送郵件(內容)    #發送郵件提醒    連接郵箱服務器    發送郵件    關閉連接def judge(self):while True:    if cpu利用率 > 90%:        發送郵件('CPU報警')    if 硬盤使用空間 > 90%:        發送郵件('硬盤報警')    if 內存佔用 > 80%:        發送郵件('內存報警')

我將每個機器創建爲一個對象,對象中有上面判斷的方法,這樣我就可以多線程的監控

2. 面向對象

  • 類和對象 
    類就是一個模板,模板裏可以包含多個方法(即函數),方法裏實現一些功能,對象則是根據模板創建的實例,通過實例對象可以執行類中的函數

  • 創建類和對象

#創建類  class+類名class foo:               #class是關鍵字,表示類,foo是類的名字def f1(self):    #類的方法1passdef f2(self):    #類的方法2pass#創建對象  對象 = 類名()bar = foo()   #創建一個bar對象 ,此對象中有類中所有的方法 ,創建對象,類名稱後加括號即可#調用對象的方法  對象.方法名()bar.f1()bar.f2()
  • 舉例:

#創建類class SQL:    def create(self,sql):        print(sql)    def modify(self, sql):        print(sql)    def remove(self,sql):        print(sql)    def fetch(self,sql):        print(sql)#創建對象obj1 = SQL()obj2 =SQL()#調用對象裏的方法res1 = obj1.modify('修改')res2 = obj2.fetch('查看')print('obj1:'res1)print('obj2:'res2)運行結果:obj1: 修改obj2: 查看
  • 應用場景

  • 面向對象:【創建對象】【通過對象執行方法】,適用於當某一些函數中具有相同參數時,可以使用面向對象的方式,將參數值一次性封裝到對象裏,函數直接調用即可

  • 函數編程:【執行函數】 各個函數之間是獨立且無共用的數據

  • 類中的self是什麼鬼 
    self是python自動傳值的一個形式參數,那個對象調用方法,就會自動執行self,在一個類中,self就是對象本身 
    還用上面的例子,如果我需要在執行方法的時候,驗證用戶名、密碼傳,驗證通過之後才能執行裏面的方法,那我需要創建對象之後,進行賦值用戶密碼

class SQL:def modify(self, sql):        print(sql)        print(self.name)        print(self.passwd)    def remove(self,sql):        print(sql)        print(self.name)        print(self.passwd)    def fetch(self,sql):        print(sql)        print(self.name)        print(self.passwd)#創建對象obj1 = SQL()obj1.user = 'user'obj1.passwd = 'passwd'res1 = obj1.modify('修改')res2 = obj2.fetch('結果')print(res1)print(res2)輸出結果:修改userpasswd結果userpasswd

我們使用self來定義user和passwd變量,這樣user和passwd對整個對象是生效的,所以在每個方法都都可以調用到

  • 類的構造方法

上例發現每次對象調用方法都要進行對user 和password進行賦值。非常麻煩。 
python類中使用init自動構造方法,當創建對象的時候自動執行該方法。如下使用init,這樣我只需要定義一次即可

class SQL:def __init__(self,user,password):  self.user = user  self.password = password    def create(self,sql):        print(sql)        print(self.name)        print(self.passwd)    def modify(self, sql):        print(sql)        print(self.name)        print(self.passwd)    def remove(self,sql):        print(sql)        print(self.name)        print(self.passwd)    def fetch(self,sql):        print(sql)        print(self.name)        print(self.passwd)obj1 = SQL('username','password')obj1.remove()obj2 = SQL('username1','password1')obj2.remove()

3. 面向對象的三大特性

  • 封裝

封裝,顧名思義就是將內容封裝到某個地方,以後再去調用被封裝在某處的內容。所以,在使用面向對象的封裝特性時,需要:

  • 將內容封裝到某處

class SQL:    def __init__(self,name,passwd):   #類的構造方法,自動執行        self.name = name        self.passwd = passwd    def create(self,sql):    #類的一個方法        print(sql,self.name,self.passwd)#創建類SQL的obj對象obj1 = SQL('fuzj','123')  #自動fuzj和123分別封裝到對象obj1的name和asswd屬性中obj2 = SQL('jie','311')  #自動jie和311分別封裝到對象obj2的name和asswd屬性中
  • 從某處調用被封裝的內容

  • 方式1 通過對象直接調用

res = obj1.name  #直接調用obj的user屬性res2 = obj1.passwd   #直接調用obj的passwd屬性print(res,res2)輸出結果:fuzj 12313
  • 方式2 通過self間接調用

res3 = obj1.create('fasdasda')print(res3)輸出結果:fasdasda fuzj 12313
  • 多重封裝

類不僅可以將普通字符串封裝到類中,還可以將一個對象封裝到類中,看下面代碼

#創建類class SQL:    def __init__(self,name,passwd):        self.name = name        self.passwd = passwd    def create(self,sql):        print(sql)class test:    def __init__(self,name,obj):        self.name = name        self.obj = obj    def add(self,arg):        print(arg)class test2:    def __init__(self,obj):        self.obj = obj    def iner(slef,arg):    print(arg)#創建對象c1 = SQL('fuzj','12313')c2 = test('aaa',c1)   #把c1對象封裝到c2對象裏,c2對象會有c1對象的所有方法c3 = test2(c2)   #把c2對象封裝到c3對象中,c3對象會有c2對象的所有方法,同時也就有了c1對象的所有方法#調用c1.create("c1調用自身create方法")c2.obj.create('c2調用c1的create方法')c3.obj.add('c3調用c2的add方法')c3.obj.obj.create('c3調用c1的create方法')結果:c1調用自身create方法c2調用c1的create方法c3調用c2的add方法c3調用c1的create方法

可以看出,將a對象封裝到b對象中,b對象也就有了a對象的所有方法, 
其關係如圖:

spacer.gif 
所以c3如果要使用c1的create的方法,需要如下調用 
c3.obj.obj.create()

  • 繼承

類的繼承是子類繼承父類的所有方法,或者說基類繼承派生類的所有方法

class 父類:    def 方法1(slef):    passclass 子類(父類):  pass那麼子類中就會有父類的方法1
* 單繼承

一個子類只繼承一個父類
如下:
class c1:    def __init__(self):        self.name = 'c1'        self.user = 'c1uer'    def test(self):        print("c1_test")    def test1(self):        print("c1_test1")    def test3(self):        self.test()class c2(c1):    def __init__(self):        self.passwd = 'c2'    def test(self):        print("c2_test")    def test2(self):        self.test3()obj = c2()obj.test()obj.test1()obj.test2()執行結果:c2_testc1_test1c2_test

繼承規則:

1) 調用子類的某個方法時,如果這個方法在子類中存在,則執行子類的方法,如果子類方法不存在,再去找父類的方法。所以執行obj.test()時,子類中有該方法,就直接執行該方法,不再父類中找,因此返回結果是c2_test;執行obj.test1()時,子類中沒有改方法,就找到父類的方法,再執行,因此返回的結果是c1_test1 
2) 子類的方法優先於父類的方法,當父類的方法中有調取其他方法時,會優先查找子類的方法,所以執行c2_test2()時,發現該方法調用的時是test3(),於是開始從自己方法中查找test3(),然後再去找父類中的方法,找到父類的test3()方法,發現該方法調用了test()方法,於是會再次查找test()方法,發現自己有,所以就直接調用自己的test()方法,返回c2_test 
3) 子類繼承父類,其實就是將父類中的方法子類中沒有的全部挪到子類下

* 多繼承

 * python的子類可以繼承多個父類,這是比java、c++等開發語言最大的優勢

單父繼承,即沒有共同的父類,規則爲一條道走到黑
class 父類1:passclass 父類2:passclass 子類(父類1,父類2)pass那麼,子類中就會有父類1,父類2的所有方法
#c4繼承了c2,c3兩個父類,c2繼承了c1父類,c3和c1中都有test()的方法class c1:    def test1(self):        print("c1_test")    def test(self):        print("c1_test")class c2(c1):    def test2(self):        print('c2_test')class c3:    def test3(self):        print("c3_test")    def test(self):        print("c3_test")class c4(c2,c3):    def test4(self):        print('c4_test')obj = c4()obj.test()obj.test3()運行結果:c1_testc3_test從結果可以看出:obj.test()執行順序爲:首先去c4類中查找,如果c4類中沒有,則繼續去c2類中找,如果c2類中沒有,則繼續去父類c1類中找,所以test()打印的結果爲c1_testobj.test3()執行順序爲:首先去c4類中查找,如果c4類中沒有,則繼續去c2類中找,如果c2類中沒有,則繼續去父類c1類中找,c1沒有,則返回繼續去另一個c4的父類c3中找,所以test3()打印的結果爲c3_test

繼承規則: 
1)子類中有兩個父類,會從左到右依次查找父類的方法 
2)子類的父類如果還有繼承,優先查找當前父類的父類 
3)多繼承的每次查找父類仍然遵循單繼承的原則 
即 
spacer.gif

同父繼承,最上邊有繼承的是一個父類,情況則不一樣了

#c4繼承c2和c3兩個父類,c2繼承c1父類,c3繼承c0父類,c0和c1繼承c父類class c:    def test(self):        print("c_test")class c0(c):    def test(self):        print("c0_test")class c1(c):    def test1(self):        print("c1_test")class c2(c1):    def test2(self):        print('c2_test')class c3(c0):    def test3(self):        print("c3_test")class c4(c2,c3):    def test4(self):        print('c4_test')obj = c4()obj.test()運行結果:c0_test查找順序爲:1.查找c4中是否有test()方法,如果沒有則查找c2中,c2中沒有則查找c1中,c1中沒有,不會繼續查找父類了,會反回來查找c3類,c3類沒有則找c0類,最後返回結果

spacer.gif 
該規則同樣適用下面情況

spacer.gif

  • 多態 
    Pyhon不支持多態並且也用不到多態,多態的概念是應用於Java和C#這一類強類型語言中,而Python崇尚“鴨子類型”

多態中python和其他編程語言最大的區別是傳參問題。python的函數傳參,參數可以是列表,字典,字符串,數字等,而java、c++等語言傳遞參數時,參數需要指定類型,一旦參數類型被指定,就只能處理此中類型的數據

  • 舉例: 
    python:

def func(arg):passarg 可以是字符串、數字、列表、字典等

java或c++

def func(int,arg)passarg 只能處理int類型的數據def func(str,arg)passarg只能處理字符串類型的數據,如果數據類型不符合的話。直接報錯
  • java如何支持多態

class A:passclass B(A):passclass C(A)passdef func(B,arg):pass此時arg指定類型爲B,那麼只能爲B的對象類型def func(A,arg)pass此時指定arg類型爲A類型,而B和C都繼承A,所以ABC類型都可以使用了所以類似java的編程語言,都是利用類的繼承關係來實現多態


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章