面向對象編程
1.編程范式
我們寫代碼的目的是什么?就是為了能夠讓計算機識別我們所寫的代碼並完成我們的需求,規范點說,就是通過編程,用特定的語法+數據結構+特殊算法來讓計算機執行特定的功能,實現一個功能的方式有很多種,對這些不同編程方式的特點進行歸納總結出來的編程方式類別,就叫做編程范式。最重要的兩個編程范式就是面向過程編程和面向對象編程。發展到現在,編程已經從簡單控制流中按步的指令集轉變為依靠代碼塊完成既定的功能。
2.面向過程編程(Procedural Programming)
面向過程是一種以過程為中心的編程思想,先分析出解決問題所需要的步驟,然后用函數把這些步驟一步一步實現,使用的時候一個一個一次調用就可以了,以孩子上學這件事用面向過程的編程思想說明的話,可以粗略的將該過程模擬為:
- 1.起床
- 2.穿衣服
- 3.洗漱吃飯
- 4.出門上學
這四步就是一步一步的完成的,它的順序很重要,只需要一步一步去實現就好了,這就是面向過程編程思想
通過下面一個例子使用面向對象的編程方法實現數據庫備份的功能,首先需要將這一事件分解為三個過程:連接數據庫-備份數據-測試,代碼如下:
def db_con():
print("連接數據庫")
def db_backup():
print("進行數據備份")
def db_backup_test():
print("備份數據可用性測試")
def main():
db_con()
db_backup()
db_backup_test()
if __name__ == "__main__":
main()
這就是面向過程的編程方式,缺點顯而易見的,如果要對該程序進行修改,那么對所修改部分有所依賴的其他部分也需要進行修改,程序越大越復雜,這種編程方式的維護難度就會越來越高,所以,如果要處理的任務是復雜的,需要不斷的迭代和維護,選擇面向對象的編程方式是更合適的。
3.面向對象編程(Object Oriented Programming)
面向對象編程思想更像是一個真實的世界,通過創建類和對象來描述這個世界,對函數進行封裝和分類,讓開發變得更快,Python從設計之初就是一門面向對象的編程語言,正因為如此,在Python中創建一個類和對象是很容易,面向對象編程其實就是對類和對象的使用。一句話:玩好面向對象,就是玩好類和對象。為了讓大家能更好的理解,我通過一個小案例來引出類和對象。
首先有這樣一個需求:有很多只小狗,需要打印出哪只小狗正在跳,通過函數的方法,我可以這樣實現:
dog_1={ 定義第一個小狗的屬性,包含小狗的姓名和年齡
"name":"AA",
"age":2,
}
dog_2={ 定義第二個小狗的屬性,包含小狗的姓名和年齡
"name":"BB",
"age":3,
}
def cry(*args):
print("一個名叫%s的%s歲小狗正在“汪汪~”的叫"%(dog_1["name"],dog_1["age"]))
cry(dog_1["name"],dog_1["age"]) 調用cry()函數
這樣寫,有如下幾個缺點:
第一:如果需要打印無數多個小狗正在叫的信息,要從dog_1定義到dog_n,這樣既會拉低效率,又會出現大量的重復代碼。
第二:如果修改了調用的小狗(如我不傳入dog_1的屬性,改為傳入dog_2),那么在函數cry()中也要進行相應的修改。那顯然是不行的。
第三:人是不具備“汪汪”叫這個動作的,我如果定義一個人的信息,按照上述的代碼寫法,也是可以調用cry()函數的,那我們怎么實現將cry()函數只提供給dog這一類使用呢?帶着這三個疑問,通過改為如下的代碼來解決上述的三個問題:
def dog(name,age): 首先定義一個狗的函數,傳入兩個參數,即小狗的姓名和年齡
def cry(dog): 在dog()函數內定義嵌套函數cry,該函數只能在函數dog()內被調用
print("一個名叫%s的%s歲小狗正在“汪汪~”的叫"%(dog["name"],dog["age"]))
def init(name,age): 定義一個初始化函數
dog_1={
"name":name,
"age":age,
"cry":cry,
}
return dog_1
return init(name,age)
d_1=dog("AA",23) 該方式實質上是通過調用init函數,生成一個具有年齡,名字的小狗d_1
print(d_1)
d_1["cry"](d_1) 調用cry函數
代碼通過這種改變,cry()就只能被狗這一類調用,在外面定義一個人的屬性去調用cry()函數,很明顯是無法調用的。
  接下來我就引出類的概念。什么是類呢?為什么要使用類*
3.1 定義類
類,既類別,種類,是面向對象設計中最重要的概念,類是一種數據結構,可以用它來定義對象,把數據值和行為特性融合在一起,在上面的例子中,小狗的屬性“姓名”、“年齡”是所有小狗都具有的屬性,這就是數據值,特定行為就是cry(),只有狗 這一類的叫聲才是“汪汪”,其它的都不具備該行為特性。定義類與定義函數很類似,定義函數使用關鍵字def
,定義類需要用到關鍵字class
  在python中,類的聲明就是通過關鍵字class
,后面緊跟一個類名如下:
def dog(): 函數
pass 函數體代碼
class dog: 類
pass 類體代碼,通常由各種各樣的定義和聲明組成
經典類與新式類的區別,經典類 class dog:
;新式類 class dog(object)
,所以如果大家見到定義類后面有括號的,一定要認得。
3.2 類對象
類對象支持兩種操作:屬性引用和實例化
屬性引用:當創建類對象的時候,所有在類命名空間中的名稱也都是有效的屬性名,對最開始說到的那個例子,我用類來實現,代碼如下:
class Dog(object): 定義一個類Dog
"這是一個小狗的類"
def __init__(self,name,age): 使用__init__函數進行初始化
self.name=name
self.age=age
def cry(self):
print("一個名叫%s的%s歲小狗正在“汪汪~”的叫"%(self.name,self.age))
d_1=Dog("AA",2) 類的實例化 -->d_1
d_1.cry() 使用創建的實例,調用類方法
屬性引用與python標准語法中所有屬性引用一樣的語法:obj.name
,在上面的例子中,Dog.name
;Dog.age
;Dog.cry
等都是有效的屬性引用,分別反饋整數和一個函數的對象。類的實例化使用函數(調用)表示法,將類對象看作是一個新的類實例的無參函數,如d_1=Dog("AA",2)
,該實例化就可以理解為:我定義了一條小狗d_1,它的名字是AA,它的年齡是2歲,這就相當於d_1={"name":AA,"age":2}
,這樣定義出來的實例,就可以調用類的特定行為函數方法。當一個類定義了__init__()方法時,類實例化會為新創建的類實例自動調用__init__()發法,會將定義時傳入的參數傳遞給該方法。
類相關知識
還是上面那個簡單的例子:
d_1=Dog("AA",2) #創建一個實例
print(Dog.color) #調用類的局部變量,類的作用於問題,我會在稍后進行詳細解答
Dog.cry(d_1) #通過類名.函數名的方式,傳入一個實例
self是代表類的實例,在定義類的時候是必須有的,但是在調用的時候不必傳入相應的參數,類的方法與普通的函數只有一個特殊的區別--它們必須有一個額外的第一個參數名稱self,self返回的是當前對象的內存地址。
python為類內置的特殊屬性
print(dir(Dog)) #返回對象的一個字符串列表的目錄
print(Dog.__name__) #返回一個類的名字
print(Dog.__bases__) #類的第一個父類(在后面叫講繼承的時候會將)
print(Dog.__doc__) #返回類的字符串文檔
print(Dog.__bases__) #類所有父類構成的元祖(同樣,在繼承的時候會將)
print(Dog.__dict__) #返回一個類的字典屬性
print(Dog.__module__) #返回類定義所在的模塊
print(d_1.__class__) #返回一個實例對應的類
類屬性的增刪改查
print(Dog.color) #查看
Dog.color = "red" #修改
print(Dog.color)
Dog.hand=4 #增加
print(Dog.hand)
del Dog.hand #刪除
print(Dog.hand)
類,其實總體就包含了兩個大的“模塊”,1.數據屬性;2.函數屬性
對象相關知識
還是這樣的一個例子:
class Dog(object):
"這是一個小狗的類"
def __init__(self,name,age):
self.name=name
self.age=age
def cry(self):
print("一個名叫%s的%s歲小狗正在“汪汪~”的叫"%(self.name,self.age))
d_1=Dog("AA",2) #實例化,實質就是在運行__init__(self,name,age)函數
d_1.cry() #創建的實例調用類中的方法,self的功能其實就是將實例自動傳入,所以我們看到,在類中定義cry函數的時候加
#了參數self,但在調用該函數的時候不需要再次傳入d_1
print(d_1.name) #調用類中的變量
Dog.cry(d_1) #將實例傳入類的方法中
實例屬性的增刪改查
d_1=Dog("aa",2)
print(d_1.name) #查看
d_1.age = 6
print(d_1.age) #修改
d_1.type = "藏獒" #增加
print(d_1.type)
del d_1.type #刪除
print(d_1.type)
類和對象的基礎用法我先講解在這里,后面的文章中會持續更新后面的知識點,喜歡我博客的朋友可以隨時關注的動態。