面向對象編程簡單來說就是基於對類和對象的使用,所有的代碼都是通過類和對象來實現的編程就是面向對象編程!面向對象的三大特性:封裝、繼承、多態首先創建一個類#使用class創建一個School類,類中有個student方法class School: def student(self): ...
面向對象編程簡單來說就是基於對 類 和 對象 的使用,所有的代碼都是通過類和對象來實現的編程就是面向對象編程!
面向對象的三大特性:封裝、繼承、多態
首先創建一個類
#使用class創建一個School類,類中有個student方法 class School: def student(self): pass a1=School()
一、封裝
1、封裝:將某些內容先封裝到一個地方,等到需要的時候再去調用
class School: def __init__(self,name,age): #構造方法,創建對象是執行 self.name=name self.age=age #創建對象a1,a2 a1=School("zhangsan",18) a2=School("lisi",18)
上面代碼實現的就是封裝的功能,把各自的name和age分別封裝到了self的name和age屬性中,就等於被封裝到了對象a1和a2中
類中定義的函數叫做方法,帶有__init__的函數稱為構造方法,在創建a1,a2對象時會自動執行。
2、調用:調用有兩種方式,通過對象直接調用和通過self間接調用
通過對象直接調用
class School: def __init__(self,name,age): self.name=name self.age=age def student(self): print("name:%s,age:%s"%(self.name,self.age)) #創建對象a1,a2 a1=School("zhangsan",18) a2=School("lisi",18) #執行結果: #name:zhangsan,age:18 #name:lisi,age:18
通過self間接調用
class School: def __init__(self,name,age): self.name=name self.age=age def student(self): print("name:%s,age:%s"%(self.name,self.age)) #創建對象a1,a2 a1=School("zhangsan",18) a2=School("lisi",18) #執行類中的方法時,通過self間接調用被封裝的內容 a1.student() a2.student() #執行結果: #name:zhangsan,age:18 #name:lisi,age:18
二、繼承
1、繼承:既派生類(子類)可以繼承基類(父類)的方法,我們可以將多個類共有的方法提取到父類當中,這樣子類僅需繼承父類而不必一一實現每個方法
在類名後面括弧中寫上另一個類,表示繼承了那個類
#使用class創建一個School類 class School: def __init__(self,name,age): self.name=name self.age=age def student(self): print("name:%s,age:%s"%(self.name,self.age)) def classroom(self): print("%s去教室"%self.name) class SchoolA(School): #SchoolA繼承School def __init__(self,name): self.name=name class SchoolB(SchoolA): #SchoolB繼承SchoolA def __init__(self,name): self.name=name #創建對象a1 a1=SchoolA("zhangsan") a1.classroom() #創建對象a2 a2=SchoolB("lisi") a2.classroom() #執行結果: # zhangsan去教室 # lisi去教室
在上面代碼中我們可以看到,在SchoolA和SchoolB中都沒有classroom方法,但由於SchoolB繼承了SchoolA,而SchoolA又繼承了School,所以他們創建對象後都能
調用School中的classroom方法。
2、多繼承
在python中,類還可以繼承多個類,在繼承多個類時,他對類中的函數查找有兩種方式
深度優先:類是經典類時,多繼承情況下,會按照深度優先方式查找
廣度優先:類是新式類時,多繼承情況下,會按照廣度優先方式查找
(在python3.x中)都預設為廣度優先,但還是可以瞭解一下兩個的區別,新式類:當前類或者基類繼承了objiect類就叫新式類,否者就是經典類
在python2.7中
#python2.7中經典類 class A(): def name(self): print("AAAAAA") class B(A): pass class C(A): def name(self): print("CCCCCC") class D(B,C): pass a1=D() a1.name() #輸出:AAAAAA #查找順序:# 首先去自己D類中查找,如果沒有,則繼續去B類中找,沒有則繼續去A類中找,沒有則繼續去C類中找,如果還是未找到,則報錯 #深度優先:D-B-A-C
#python2.7中新式類 class A(object): def name(self): print("AAAAAA") class B(A): pass class C(A): def name(self): print("CCCCCC") class D(B,C): pass a1=D() a1.name() #輸出:CCCCCC #查找順序:# 首先去自己D類中查找,如果沒有,則繼續去B類中找,沒有則繼續去C類中找,沒有則繼續去A類中找,如果還是未找到,則報錯 #廣度優先:D-B-C-A
上面兩個例子中我們可以看到,經典類和新式類輸出的結果是不一樣的,是因為他們的查找順序不一樣
python2.7中 廣度優先的前提條件:D繼承BC,BC又同時繼承A,只有滿足這個條件,新式類才會遵循廣度優先,否者不會,例:
class A(object): def name(self): print("AAAAAA") class B(A): pass class C: def name(self): print("CCCCCC") class D(B,C): pass a1=D() a1.name() #輸出:AAAAAA
如果C不在繼承A,那麼就算你是新式類,他也會按照深度優先的順序查找
在python3.X之後就沒有了上面的這些區別,它的查找順序都是 廣度優先
三、多態
python不支持多態,也用不到多態,python是一種多態語言,崇尚鴨子類型
四、類中的成員
類中的成員:欄位、方法、屬性
1、欄位
欄位:普通欄位、靜態欄位
class School: headmaster="王五" def __init__(self,name,age): self.name=name self.age=age def student(self): print("name:%s,age:%s"%(self.name,self.age)) #創建對象a1 a1=School("zhangsan",18) print(a1.name) #訪問普通欄位 print(School.headmaster) #訪問靜態欄位 #執行結果: # zhangsan # 王五
在上面代碼中,__init__函數中的就是普通欄位,headmaster就是靜態欄位
普通欄位:屬於對象,由對象來訪問,在記憶體中每個對象都要保存一份
靜態欄位:屬於類,由類直接訪問,在記憶體中只保存一份
2、方法
方法:普通方法、靜態方法、類方法
class School: headmaster="王五" def __init__(self,name,age): self.name=name self.age=age def student(self): #普通方法 至少一個self print("普通方法") @staticmethod #靜態方法 任意參數 def classroom(): print("靜態方法") @classmethod def dormitory(cls): #類方法 只能一個cls print("類方法",cls) #創建對象a1 a1=School("zhangsan",18) a1.student() School.classroom() #訪問靜態方法 School.dormitory() #訪問類方法 '''執行結果: 普通方法 靜態方法 類方法 <class '__main__.School'> '''
普通方法:先創建一個對象,在用對象去調用這個方法
靜態方法:直接用類調用,可以有任意參數(靜態方法可以讓類直接調用,省去了普通方法創建對象的步驟)
類方法:直接用類調用,只能一個cls參數
上面我們可以看到執行類方法時,輸出了他傳入的參數等於<class '__main__.School'>,是一個類,意思就是執行時,它會把當前的類當成參數傳進去。
3、屬性
屬性定義:裝飾器定義、靜態欄位定義
(1)裝飾器定義
class School: headmaster="王五" def __init__(self,name,age): self.name=name self.age=age def student(self): #方法 print("方法") @property def classroom(self): #屬性,加上@property裝飾器,僅有一個self參數 print("屬性") #創建對象a1 a1=School("zhangsan",18) a1.student() #調用方法 a1.classroom #調用屬性 #執行結果: # 方法 # 屬性
在上面代碼中可以看到,在方法上加上@property裝飾器就叫屬性,屬性和方法的區別就是調用時不用加括弧
在新式類中,除了@property,還有另外兩種裝飾器
class School(object): def __init__(self,name,age): self.name=name self.age=age @property def classroom(self): #屬性,加上@property裝飾器,僅有一個self參數 print(self.name,self.age) @classroom.setter def classroom(self,age): self.age=age #把age修改為傳入的參數 print("修改",self.name,self.age) @classroom.deleter def classroom(self): del self.age #刪除age print("刪除",self.name,self.age) #創建對象a1 a1=School("張三",18) a1.classroom #1.執行後會自動調用@property方法 a1.classroom=20 #2.執行後會自動調用@classroom.setter的方法,並將20傳給age參數 del a1.classroom #3.執行後會自動調用@classroom.deleter的方法 '''執行結果: 張三 18 修改 張三 20 在執行3時會報錯,因為age已經在@classroom.deleter下麵的方法里刪除了,所以輸出self.age時會出錯 '''
(2)靜態欄位定義
class School(object): def __init__(self,name,age): self.name=name self.age=age def classroom(self): print(self.name,self.age) def classroom_update(self,age): self.age=age #把age修改為傳入的參數 print("修改",self.name,self.age) def classroom_del(self): del self.age #刪除age print("刪除",self.name,self.age) obj=property(classroom,classroom_update,classroom_del) #靜態欄位方式定義屬性 #創建對象a1 a1=School("張三",18) a1.obj #1.執行後會自動調用classroom方法 a1.obj=20 #2.執行後會自動調用classroom_update的方法,並將20傳給age參數 del a1.obj #3.執行後會自動調用classroom_delr的方法
4、公有成員和私有成員
在類中的每一個成員都有兩種形式:公有、私有
公有:都可以訪問 私有:只有在類的內部可以訪問
舉幾個例子
欄位
class School(object): deg="狗" #公有靜態欄位 __cat="貓" #私有靜態欄位 def __init__(self,name,age): self.name=name #公有普通欄位 self.__age=age #私有普通欄位 def dormitory(self): print(self.__age) def cat(self): print(School.__cat) #創建對象a1 a1=School("張三",18) #訪問普通欄位 print(a1.name) #輸出:張三 print(a1.age) #報錯,提示沒有age,因為age是私有欄位,只能間接內部訪問 a1.dormitory() #只能通過類內部訪問私有欄位 #訪問靜態欄位 print(School.deg) #輸出:狗 print(School.__cat) #報錯 a1.cat() #輸出:貓 可以間接通過內部的cat方法反問私有靜態欄位
方法
class School(object): def __init__(self,name,age): self.name=name self.__age=age def cat(self): #公有方法 print("cat") def __dog(self): #私有方法 print("dog") def doo(self): #內部訪問私有方法 a1.__dog() #創建對象a1 a1=School("張三",18) a1.cat() #輸出:cat a1.dog() #報錯 a1.doo() #輸出:dog 間接通過doo方法反問私有方法__dog
類中的其他成員也和上面的類似
5、類中的特殊成員
(1)__doc__
class School(object): """類的描述信息""" def __init__(self,name,age): self.name=name self.__age=age print(School.__doc__) #輸出:類的描述信息
(2)__init__
在上面已經說過,在創建對象是自動執行
(3)__del__
當對象在記憶體中被釋放時,自動觸發執行
(4)__call__
在創建的對象後面加括弧執行時,會自動執行類里的__call__方法
class School(object): def __call__(self, *args, **kwargs): print("觸發__call__方法") a1=School() a1() #輸出:觸發__call__方法 School()() #輸出:觸發__call__方法
(5)__dict__
獲取類或對象的所有成員
class School(object): """類的描述信息""" cat="貓" def __init__(self,name,age): self.name=name self.__age=age def dog(self): print("dog") print(School.__dict__) #獲取類中的成員 a1=School("張三",18) print(a1.__dict__) #獲取對象中的成員 ''' 輸出: {'cat': '貓', '__init__': <function School.__init__ at 0x000000000226C950>, '__dict__': <attribute '__dict__' of 'School' objects>, '__weakref__': <attribute '__weakref__' of 'School' objects>, '__module__': '__main__', 'dog': <function School.dog at 0x000000000226CAE8>, '__doc__': '類的描述信息'} {'name': '張三', '_School__age': 18} '''
(6)__str__
沒有__str__
class School(object): def __init__(self,name,age): self.name=name self.__age=age a1=School("張三",18) print(a1) #輸出:<__main__.School object at 0x000000000222B278>
有__str__
class School(object): def __init__(self,name,age): self.name=name self.__age=age def __str__(self): return("print對象時的返回值") a1=School("張三",18) print(a1) #輸出:print對象時的返回值
其他的特殊成員就不一一列舉了,因為大多數情況下也不會用到
詳細請看:http://www.cnblogs.com/wupeiqi/p/4766801.html