咱們都知道Python是一門靈活度很高的語言,它能夠面向過程,面向對象,那咱們今天說說Python中的面向對象設計和麪向對象編程的區別python
面向對象設計和麪向對象編程都提到了「面向對象」, 那麼首先咱們要搞清楚什麼是對象編程
對象:咱們能夠簡單的理解爲咱們見到的每一個實際存在的事物就是一個對象,若是一我的,一座房子,一隻小貓等。bash
那麼咱們想一想,咱們怎麼面向對象,那就是以對象爲中心,去描述這個對象,這個對象有什麼特色,什麼屬性,什麼功能等,想一想假如你要去向別人描述一個丟失的小貓(一個對象),你要怎麼描述呢?小夠的品種,大小,毛色,等等。 當你把着一些特徵或者屬性描述清楚以後,一個對象就被定義下來了。編程語言
知道對象的概念以後,咱們進入主題函數
說到設計,咱們能夠理解爲是一種想法,思路,就是把對象的屬性,功能(python裏用函數表達)糅合在一塊兒造成一個對象,這種思想能夠簡單的理解爲面向對象設計,不是說必須用CLASS這種,才叫面向對象設計,下面咱們舉個例子ui
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)
複製代碼
結果spa
{'name': '毛球', 'gender': '公', 'type': '波斯貓', 'cry': <function cat.<locals>.cry at 0x0000022C6C9B71E0>, 'run': <function cat.<locals>.run at 0x0000022C6C9B7158>}
一條小貓[毛球],喵喵
複製代碼
上面咱們用純函數的方式去描述了一隻小貓,可是咱們也能夠把上面這張方式理解爲面向對象設計,由於上面咱們把貓的屬性和功能函數結合在一塊兒,形式了一個對象。設計
咱們用code
cat=cat('毛球','公','波斯貓')
複製代碼
來生成一個對象,咱們能夠調用對象的屬性和函數等等,這些都是咱們熟悉的面向對象設計,可是咱們不能說這種方式叫面向對象編程。cdn
這個在不少語言中都在大量使用,簡單的說使用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.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