python3之面向對象
1、面向對象術語
- 類(Class): 用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實例。
- 類屬性(類變量):類屬性在整個實例化的對象中是公用的。類屬性定義在類中且在函數體之外。類變量通常不作為實例變量使用。
- 數據成員:類變量或者實例變量用於處理類及其實例對象的相關的數據。
- 方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個過程叫方法的覆蓋(override),也稱為方法的重寫。
- 實例變量:定義在方法中的變量,只作用於當前實例的類。
- 繼承:即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作為一個基類對象對待。例如,有這樣一個設計:一個Dog類型的對象派生自Animal類,這是模擬"是一個(is-a)"關系。
- 實例化:創建一個類的實例,類的具體對象。
- 方法:類中定義的函數。
- 對象:通過類定義的數據結構實例。對象包括兩個數據成員(類變量和實例變量)和方法。
2、類定義
Python中的類提供了面向對象編程的所有基本功能:類的繼承機制允許多個基類,派生類可以覆蓋基類中的任何方法,方法中可以調用基類中的同名方法。
對象可以包含任意數量和類型的數據。
class test(object): #定義一個類,在3.5中必須指定基類object i = 123 #類變量 def func(self): #類方法 print(‘第一個類‘) return ‘hell python‘ s = test() #通過類實例化對象 str = s.func() #對象調用類方法 print(test.i) #通過類名調用類變量 print(str) #類返回值 #output 第一個類 123 hell python
類實例化後,可以使用其屬性,實際上,創建一個類之後,可以通過類名訪問其屬性和方法;實例化類後可以使用其屬性,也可以動態的為實例對象添加屬性而不影響類對象。
可以使用點(.)來訪問對象的屬性,也可以使用函數的方式來訪問屬性:
class A(object):def __init__(self,x): self.x = x def static_func(y=5): print(y) d = A(10) #類實例化對象 print(getattr(d,‘x‘)) #getattr訪問對象的屬性 print(hasattr(d,‘x‘)) #hasattr檢查對象屬性是否存在 print(setattr(d,‘y‘,‘zhang‘)) #設置對象的屬性,如果屬性不存在則創建新屬性 print(d.y) #打印實例對象屬性值 delattr(d,‘y‘) #defattr刪除對象屬性 print(hasattr(d,‘x‘)) #output 10 True None zhang True
python3內置類屬性:
__dict__:類的屬性(包含一個字典,由類的數據屬性組成)
__doc__:類的文檔字符串
__name__:類名
__module__:類定義所在的模塊(類的全名是‘__main__.className’,如果類位於一個導入模塊mymod中,那麽className.__module__等於mymod)
__bases__:類的所有父類構成元素(包含了以上所有父類組成的元組)
class myclass(object): class_n = ‘foo‘ def __init__(self,x,y,z): self.x = x self.y = y self.z = z def func_class(self): print(‘out:‘,self.x,self.y,self.z) t = myclass(‘10‘,‘20‘,‘50‘) t.func_class() #調用實例方法 print(‘__dict__:‘,myclass.__dict__) #返回類的屬性 print(‘__dict__:‘,t.__dict__) #返回實例屬性 print(‘__name__:‘,myclass.__name__) #返回類名 print(‘__doc__:‘,myclass.__doc__) print(‘__module__:‘,myclass.__module__) #返回類屬在的模塊 print(‘__mro__:‘,myclass.__mro__) print(‘__bases__:‘,myclass.__bases__) #返回類對象 #output out: 10 20 50 __dict__: {‘__init__‘: <function myclass.__init__ at 0x0000004249F0F378>, ‘__doc__‘: None, ‘func_class‘: <function myclass.func_class at 0x0000004249F0F400>, ‘class_n‘: ‘foo‘, ‘__dict__‘: <attribute ‘__dict__‘ of ‘myclass‘ objects>, ‘__module__‘: ‘__main__‘, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘myclass‘ objects>} __dict__: {‘x‘: ‘10‘, ‘z‘: ‘50‘, ‘y‘: ‘20‘} __name__: myclass __doc__: None __module__: __main__ __mro__: (<class ‘__main__.myclass‘>, <class ‘object‘>) __bases__: (<class ‘object‘>,)
類的專有方法:
-
__init__ 構造函數,在生成對象時調用
-
__del__ 析構函數,釋放對象時使用
-
__repr__ 打印,轉換
-
__setitem__按照索引賦值
-
__getitem__按照索引獲取值
-
__len__獲得長度
-
__cmp__比較運算
-
__call__函數調用
-
__add__加運算
-
__sub__減運算
-
__mul__乘運算
-
__div__除運算
-
__mod__求余運算
-
__pow__乘方
__init__()方法是一種特殊的方法,被稱為類的構造函數或初始化方法,當創建了這個類的實例時就會調用該方法,類定義了__init__()方法後,類的實例化操作會自動調用__init__()方法,__init__()可以由參數,會傳遞到類的實例化操作上。
self代表類的實例,而非類本身,在類的內部,使用def關鍵字來定義一個方法,與一般函數定義不同,類方法必須包含self,且為第一個參數,self代表的是類的實例。
class test(object): def __init__(self,name,age,salary): #初始化類屬性 self.name = name self.age = age self.salary = salary #實例化對象會將類初始化到實例對象上 def buygo(self): print(‘%s的工資是%s元‘ %(self.name,self.salary)) #調用類屬性 #通過類實例化對象 zhansan = test(‘zhansan‘,20,8888) lisi = test(‘lisi‘,22,6000) #調用類方法 zhansan.buygo() lisi.buygo() #output: #zhansan的工資是8888元 #lisi的工資是6000元
class test1(object): a = 10 b = 20 def get(self): print(‘取冪:‘,self.a.__pow__(self.b)) print(‘求余數:‘,self.b.__mod__(self.a)) print(‘乘:‘,self.b.__mul__(self.a)) print(‘減:‘,self.b.__sub__(self.a)) print(‘加:‘,self.b.__add__(self.a)) print(‘輸出:‘,self.b.__repr__()) d = test1() d.get() #output 取冪: 100000000000000000000 求余數: 0 乘: 200 減: 10 加: 30 輸出: 20
實例方法,類方法,靜態方法,類屬性,實例屬性:
#實例方法,就是類的實例能夠使用的方法 class myclass(object): def __init__(self,name): self.name = name def instancefunc(self): print(‘調用實例方法%s‘%self.name) if __name__ == "__main__": inst = myclass(‘zhangsan‘) #通過類創建實例 inst.instancefunc() #實例使用實例方法 myclass.instancefunc(inst) #類使用實例方法,需要傳遞實例參數
#類方法是將類本身作為對象進行操作的方法,類方法使用@classmethod裝 #飾器定義,其第一個參數是類,約定為cls,也可以自己定義,類對象和實例 #都可以調用類方法,類方法只能調用類屬性,不能調用實例屬性。 class A(object): number = 10 #定義類屬性 def __init__(self,name): #初始化類屬性 self.name = name def car(self): #定義實例方法 print(‘實例方法:%s‘%self.name) @classmethod #定義類方法 def cat(cls): print(‘類方法:%s‘%cls.number) #此處不能調用類屬性name,只能調用類屬性number d = A(‘sb‘) d.car() #實例調用實例方法 d.cat() #實例調用類方法 A.cat() #類調用類方法 #output 實例方法:sb 類方法:10 類方法:10
#靜態方法是一種普通函數,就位於類定義的命名空間中,它不會對任何實例類 #型進行操作。使用裝飾器@staticmethod定義靜態方法。類對象和實例都可 #以調用靜態方法,靜態方法不能調用類屬性和實例屬性,但可以調用傳參。 class A(object): number = 10 def __init__(self,name): self.name = name def car(self): print(‘實例方法:%s‘%self.name) @staticmethod #定義靜態方法 def cat(x,y): #定義調用傳參 print(‘靜態方法:%s‘%(x*y)) d = A(‘sb‘) #實例化類 d.car() #實例方法 d.cat(5,4) #實例調用靜態方法 A.cat(6,3) #類調用靜態方法 #output 實例方法:sb 靜態方法:20 靜態方法:18
#類屬性與實例屬性在實例方法,類方法,靜態方法中的調用關系 class A(object): number = 10 #定義類屬性 def __init__(self,name): self.name = name #實例屬性 def car(self): #實例方法可以調用類屬性和實例屬性 print(‘實例方法:%s[%s]‘%(self.name,self.number)) @classmethod def cae(cls): #類方法只能調用類屬性 print(‘類方法:%s‘%cls.number) @staticmethod def cat(x,y): #靜態方法不能調用類屬性和實例屬性 print(‘靜態方法:%s‘%(x*y)) d = A(‘sb‘) d.car() A.car(d) d.cae() #實例調用方法 A.cae() #類調用方法 d.cat(5,4) A.cat(6,3) #output 實例方法:sb[10] 實例方法:sb[10] 類方法:10 類方法:10 靜態方法:20 靜態方法:18
3、類的封裝
封裝是面向對象的特征之一,是對象和類概念的主要特性。
封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。
python通過變量名命名來區分屬性和方法的訪問權限,默認權限相當於c++和java中的public
類的私有屬性: __private_attrs:兩個下劃線開頭,聲明該屬性為私有,不能在類地外部被使用或直接訪問。在類內部的方法中使用時self.__private_attrs。
類的私有方法:__private_method:兩個下劃線開頭,聲明該方法為私有方法,不能在類地外部調用。在類的內部調用 self.__private_methods
class myclass(object): def __init__(self,name,age): #構造方法,根據類創建對象時自動執行 self.name = name self.age = age def func(self): print(‘%s今年%s‘%(self.name,self.age)) #根據類創建對象,會自動執行類的__init__方法 obj1 = myclass(‘zs‘,18) #會將zs和18分別封裝到類的self的name和age屬性中 obj2 = myclass(‘ls‘,20) print(obj1.name,obj1.age) #直接調用obj1對象的屬性 print(obj2.name,obj2.age) obj1.func() #默認會將obj1傳遞給self參數,即:obj1.func(obj1),所以此方法的內部self=obj1,self.name是zs obj2.func() #output zs 18 ls 20 zs今年18 ls今年20
class fater(object): __name = ‘私有屬性‘ age = "公有屬性" def func(self): print(self.age) print(self.__name) def __foo(self): #定義私有方法 print(self.__name) class son(fater): def show(self): print(fater.age) #print(fater.__name) print(fater.age) print(‘----------------‘) obj1 = fater() obj1.func() print(‘----------------‘) #obj1.__foo() #直接調用會報錯,只有通過"_類名__方法"的形式調用 obj1._fater__foo() #調用私有方法 print(obj1.age) #print(obj1.__name) #直接調用會報錯,通過“_類名__屬性”方法調用 print(obj1._fater__name) #調用私有屬性 print(‘-------son----‘) obj2 = son() obj2.show() #調用父類屬性 obj2.func() obj2.__foo() #調用父類方法錯誤 obj2._fater__foo() #正確調用父類方法 #output 公有屬性 ---------------- func: 公有屬性 func: 私有屬性 ---------------- __foo: 私有屬性 公有屬性 私有屬性 -------son---- show: 公有屬性 func: 公有屬性 func: 私有屬性 __foo: 私有屬性
4、類繼承
繼承是面向對象的重要特征之一,繼承是兩個類或者多個類之間的父子關系,子類繼承了父類的所有公有實例變量和方法。
繼承實現了代碼的重用。重用已經存在的數據和行為,減少代碼的重新編寫。
python在類名後用一對圓括號表示繼承關系,括號中的類表示父類或基類
#經典類和新式類的區別:當前類或者父類繼承了object類,那麽該類便是新式類,否則便是經典類。 class old: #經典類寫法 pass class new(object): #新式類寫法 pass
在python中類繼承的特點:
1:在繼承中基類的構造(__init__()方法)不會被自動調用,它需要在其派生類的構造中親自專門調用。使用super().__init__()或parentClassName.__init__()
2:在調用基類的方法時,需要加上基類的類名前綴,且需要帶上self參數變量。區別於在類中調用普通函數時並不需要帶上self參數
3:Python總是首先查找對應類型的方法,如果它不能在派生類中找到對應的方法,它才開始到基類中逐個查找。(先在本類中查找調用的方法,找不到才去基類中找)。
如果在繼承元組中列了一個以上的類,那麽它就被稱作"多重繼承" 。
class test(object): #定義父類 def __init__(self,name,age,salary): self.name = name self.age = age self.salary = salary def buygo(self): print(‘%s[%s]歲就有%s元的工資了‘ %(self.name,self.age,self.salary)) class test_student(test): #調用父類 def __init__(self,name,age,salary,nb): test.__init__(self,name,age,salary) #重寫父類構造方法 self.nb = nb def buygo(self): #覆寫類方法 print(‘%s[%s]歲就有%s元的工資了,很%s‘ %(self.name,self.age,self.salary,self.nb)) #通過類實例化對象 zhansan = test_student(‘zhansan‘,20,8888,‘牛逼哦‘) lisi = test_student(‘lisi‘,22,6000,‘得瑟吧‘) zhansan.buygo() lisi.buygo() #output: zhansan[20]歲就有8888元的工資了,很牛逼哦 lisi[22]歲就有6000元的工資了,很得瑟吧
如果父類中的方法名相同於子類中的方法名,子類方法將覆蓋父類方法。
多繼承的優先級順序是:在新式類中是從左往右查找,找到即停止;而經典類是深度查找的從左到右如:A(B,C),B(D),那麽順序是A->B->D->C
5、多態
多態依賴於繼承,多態的作用,就是為了類在繼承和派生的時候,保證繼承類中實例的某個屬性或方法的調用,實現了接口的重用。class A(object): def __init__(self):
self.name = ‘ZHANGSAN‘ def show(self): print(‘A.show:‘,self.name) class B(A): def show(self): print(‘show_b:‘,self.name) class C(A): def show(self): print(‘show_c:‘,self.name) def func(obj): #定義函數,傳遞對象 obj.show() #通過類實例對象調用類下的方法 A_obj = A() B_obj = B() C_obj = C() func(A_obj) func(B_obj) func(C_obj)
#output
A.show: ZHANGSAN
show_b: ZHANGSAN
show_c: ZHANGSAN
6、總結
- 面向對象的知識總計如下:
- 面向對象時一個編程方式,此編程方式的實現是基於對類和對象的使用
- 類是一個模版,模版中包裝了多個‘函數’供使用
- 對象根據模塊創建實例,實例可以調用被包裝在類中的函數
- 繼承實現了多個類直接的方法屬性調用,減少代碼的重用性
- 多態在繼承的基礎上解決了方法調用的重用,而不被子類給覆蓋。
- 面向對象的三大特性:封裝、繼承和多態
python3之面向對象