我們都知道Python是一門靈活度很高的語言,它可以面向過程,面向對象,那我們今天說說Python中的面向對象設計和麪向對象編程的區別
面向對象設計和麪向對象編程都提到了“面向對象”, 那麼首先我們要搞清楚什麼是對象
對象:我們可以簡單的理解爲我們見到的每個實際存在的事物就是一個對象,如果一個人,一座房子,一隻小貓等。
那麼我們想想,我們怎麼面向對象,那就是以對象爲中心,去描述這個對象,這個對象有什麼特點,什麼屬性,什麼功能等,想想假如你要去向別人描述一個丟失的小貓(一個對象),你要怎麼描述呢?小夠的品種,大小,毛色,等等。 當你把着一些特徵或者屬性描述清楚之後,一個對象就被定義下來了。
知道對象的概念之後,我們進入主題
1.面向對象設計
說到設計,我們可以理解爲是一種想法,思路,就是把對象的屬性,功能(python裏用函數表達)糅合在一起形成一個對象,這種思想可以簡單的理解爲面向對象設計,不是說必須用CLASS這種,才叫面向對象設計,下面我們舉個例子
def cat(name,gender,type):
# 貓的的動作或者叫功能
def cry(cat):
print('一條小貓[%s],喵喵' % cat['name'])
def run(cat):
print('一條[%s]小貓正在跑' % cat['type'])
def init(name,gender,type):
cat = {
'name':name,
'gender': gender,
'type': type,
'cry':cry,
'run':run,
}
return cat
return init(name,gender,type)
cat=cat('毛球','公','波斯貓')
print(cat)
cat['cry'](cat)
結果
{'name': '毛球', 'gender': '公', 'type': '波斯貓', 'cry': <function cat.<locals>.cry at 0x0000022C6C9B71E0>, 'run': <function cat.<locals>.run at 0x0000022C6C9B7158>}
一條小貓[毛球],喵喵
上面我們用純函數的方式去描述了一隻小貓,但是我們也可以把上面這張方式理解爲面向對象設計,因爲上面我們把貓的屬性和功能函數結合在一起,形式了一個對象。
我們用
cat=cat('毛球','公','波斯貓')
來生成一個對象,我們可以調用對象的屬性和函數等等,這些都是我們熟悉的面向對象設計,但是我們不能說這種方式叫面向對象編程。
2.面向對象編程,
這個在很多語言中都在大量使用,簡單的說使用Class來描述對象的方式就是面向對象編程。Python中當然也可以使用面向對象編程,但是不強求,如JAVA之類的編程語言就強制要求使用面向對象編程,個人認爲不太友好。下面我們把上面的例子改成面向對象編程的方式來看看
class Cat:
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
def cry(self):
print('一條小貓[%s],喵喵' % self.name)
def run(self):
print('一條[%s]小貓正在跑' % self.type)
cat = Cat('毛球','公','波斯貓')
print(Cat)
cat.cry()
上面我們改成了個class的方式來編程,可以說就是使用面向對象編程的方式。也是我們熟悉的類方式。
3.面向對象編程的基礎知識點撥
3.1類和函數的屬性分類
類屬性包含:數據屬性和函數屬性
對象屬性包括:數據屬性,對象如果向調用函數屬性,其實是調用的類的函數屬性
類的數據屬性是所有對象共享的
類的函數屬性是綁定給對象用的
怎麼理解呢?我們可以使用__dict__方法來看屬性
class Cat:
weight = 5; #新定義了一個類的數據屬性
def __init__(self,name,gender,type): #實例屬性
self.name = name
self.gender = gender
self.type = type
def cry(self): #類的函數屬性
print('一條小貓[%s],喵喵' % self.name)
def run(self): #類的函數屬性
print('一條[%s]小貓正在跑' % self.type)
cat = Cat('毛球','公','波斯貓')
print(Cat.__dict__)
print(cat.__dict__)
結果
{'__module__': '__main__', 'weight': 5, '__init__': <function Cat.__init__ at 0x0000021E5DC671E0>, 'cry': <function Cat.cry at 0x0000021E5DC67158>, 'run': <function Cat.run at 0x0000021E5DC67268>, '__dict__': <attribute '__dict__' of 'Cat' objects>, '__weakref__': <attribute '__weakref__' of 'Cat' objects>, '__doc__': None}
{'name': '毛球', 'gender': '公', 'type': '波斯貓'}
上面一行是類的屬性,我們可以看到我們定義的weight,'cry','run'等類的數據和函數屬性
下面一行是對象的屬性,只有init裏面定義的數據屬性,沒有函數屬性
當函數想調用方法時,是先從自己的屬性裏面找,如果沒有就去上層類的__dict__裏面去尋找,執行,所以我們說對象執行方法其實執行的是類的函數屬性。
我們看到上面__dict__裏面還有一些其他自帶屬性解釋如下
#python爲類內置的特殊屬性
類名.__name__# 類的名字(字符串)
類名.__doc__# 類的文檔字符串
類名.__base__# 類的第一個父類(在講繼承時會講)
類名.__bases__# 類所有父類構成的元組(在講繼承時會講)
類名.__dict__# 類的字典屬性
類名.__module__# 類定義所在的模塊
類名.__class__# 實例對應的類(僅新式類中)
3.2 self到底什麼意思,什麼時候使用
self我們可以理解爲實例對象自己,那爲什麼在面向對象編程的時候,類的每個函數都要在第一個參數放self呢? 我的理解一方面是面向對象編程的語法需要,二深層次的說是把類的數據屬性和函數屬性糅合在一起,滿足面向對象設計的思想
self在對象實例化的時候,會自動傳入,如果函數屬性裏面不定義self會報錯
class Cat:
weight = 5;
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
def cry(): #沒有寫self
print('一條小貓喵喵')
def run(self):
print('一條[%s]小貓正在跑' % self.type)
cat = Cat('毛球','公','波斯貓')
cat.cry() #對象調用類的函數屬性時候,會自己傳入self也就是實例自己,作爲第一個參數
結果報錯
Traceback (most recent call last):
File "C:/Users/aryin/Desktop/mysite2/面向對象.py", line 14, in
cat.cry()
TypeError: cry() takes 0 positional arguments but 1 was given
仔細看報錯,cry() takes 0 positional arguments but 1 was given,說我們給它傳了一個參數,但是上面的代碼裏,我們什麼也沒傳,所以這是python自己給我們默認傳了一個self參數
那我們看看我們直接用類自己來調用它的函數屬性,看看會不會自己傳入self參數
class Cat:
weight = 5;
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
def cry(self): #沒有寫self
print('一條小貓喵喵')
def run(self):
print('一條[%s]小貓正在跑' % self.type)
cat = Cat('毛球','公','波斯貓')
Cat.cry() #類調用自己的函數屬性,不傳入參數
結果報錯
Traceback (most recent call last):
File "C:/Users/aryin/Desktop/mysite2/面向對象.py", line 15, in
Cat.cry()
TypeError: cry() missing 1 required positional argument: 'self'
看錯誤是少了一個參數,說明當類自己調用函數屬性的時候,不會自己傳入self,cry函數需要一個參數self,所以報錯了,所以正確的使用是
class Cat:
weight = 5;
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
def cry(self): #沒有寫self
print('一條小貓喵喵')
def run(self):
print('一條[%s]小貓正在跑' % self.type)
cat = Cat('毛球','公','波斯貓')
Cat.cry(cat) #類調用自己的函數屬性,不傳入參數
所以只有當對象去調用類的函數屬性或者說方法的時候纔會自動傳入self屬性,類自己調用時候不會,要自己傳入實例。
當然我們一般不這麼使用類來調用自己的函數屬性,我們可以使用類方法來實現調用
class Cat:
weight = 5;
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
@classmethod
def cry(cls): #沒有寫self print('一條小貓喵喵')
def run(self):
print('一條[%s]小貓正在跑' % self.type)
Cat.cry()
結果:
一條小貓喵喵
這裏看到改動的地方,是傳入的cls, 就是類自己,classmethod類靜態方法實現類調用自己的函數屬性時候不需要顯示傳入cls參數,而是自動傳入,classmethod類靜態方法實際就是綁定了類和自己的函數屬性。
3.3 實例化到底做了什麼(__init__方法)
當對象實例化的時候,會先去執行__init__函數,對象會去__init__裏面找到自己的數據屬性
class Cat:
weight = 5;
def __init__(self,name,gender,type):
print('開始初始化')
self.name = name
self.gender = gender
self.type = type
print('結束初始化')
def cry(self): #沒有寫self
print('一條小貓喵喵')
def run(self):
print('一條[%s]小貓正在跑' % self.type)
cat=Cat('毛球','公','波斯貓') #實例化
print(cat.__dict__)
結果:
開始初始化
結束初始化
{'name': '毛球', 'gender': '公', 'type': '波斯貓'}
看到__init__函數裏面已經執行了,對象的數據屬性也得到了。
今天說到這裏,個人意見,望指教。
更多源代碼文章請關注:pythonislover