Python 面向對象的進階
類的成員
類的成員可以分為三大類 : 字段 , 方法 和 屬性
註 : 所有的成員中,只有普通字段的內容保存對象中, 即 : 根據此類創建了對象,在內存就有多少個普通字段. 而其他的成員,則都是保存在類中 , 即 : 無論對象的多少,在內存中只創建一份.
一 , 字段
字段包括 : 普通字段和靜態字段,他們在定義和使用中有所區別,而最本質的區別是內存中保存的位置不同.
- 普通字段屬於對象
- 靜態字段屬於類
1 class Province: 2 """ 3 字段的定義和使用 4 """ 5 # 靜態字段 6 country = "中國" 7 def __init__(self,name): 8 9 # 普通字段 10 self.name = name 11 12 # 直接訪問普通字段 13 obj = Province("和順") 14 print(obj.name) 15 16 # 直接訪問靜態字段 17 print(Province.country)字段的定義和使用
有上述代碼可以看出 [普通字段需要通過對象來訪問] [靜態字段通過類訪問] , 在使用上可以看出普通字段和靜態字段的歸屬是不同的,其在內容的存儲方式類似如下圖:
右上圖可知:
- 靜態字段在內存中只存一份
- 普通字段在每個對象中都要保存一份
應用場景 : 通過類創建對象時 , 如果每個對象都具有相同的字段,那麽就使用靜態字段
二 方法
方法包括 : 普通方法 , 靜態方法 , 和 類方法 , 三種方法在內存中都歸屬類 , 區別在於調用方式不同
- 普通方法 : 由對象調用 ; 至少一個self
- 類方法 : 由類調用 ; 至少一個cls 參數 ; 執行類方法時 , 自動將調用該方法的類賦值給cls;
- 靜態方法 : 由類調用 ; 無默認參數;
1 class Foo: 2 3 def __init__(self,name): 4 self.name = name 5 6 def ord_func(self): 7 ‘‘‘ 8 定義一個普通方法,至少有一個self參數 9 ‘‘‘ 10 print(self.name) 11 print("普通方法") 12 13 @classmethod 14 def class_func(cls): 15 ‘‘‘ 16 定義一個類方法,至少有一個cls參數 17 ‘‘‘ 18 print("類方法") 19 20 @staticmethod 21 def static_func(): 22 """ 23 定義一個靜態類方法, 無需默認參數 24 """ 25 print("靜態類方法") 26 27 # 調用普通方法 28 f = Foo("和順") 29 f.ord_func() 30 31 # 調用類方法 32 Foo.class_func() 33 34 # 調用靜態類方法 35 Foo.static_func()方法的定義和使用
相同點 : 對於所有的方法而言 , 均屬於類(非對象) 中 , 所以 , 在內存中也只保存一份.
不同點 : 方法調用者不同 , 調用方法時自動轉入的參數不同
三 屬 性
如果你已經了解Python類中的方法 , 那麽屬性就非常簡單了 , 因為Python中的屬性其實是普通方法的變種
對於屬性 ,有三個知識點
- 屬性的基本使用
- 屬性的兩種定義方式
1 , 屬性的基本使用
1 class Foo: 2 3 def func(self): 4 pass 5 # 定義屬性 6 @property 7 def prop(self): 8 pass 9 10 foo_obj = Foo() 11 foo_obj.func() 12 foo_obj.prop # 調用屬性屬性的定義和是使用
由屬性的定義和調用要註意一下幾點:
- 定義時 , 在普通方法的基礎上添加 @property 裝飾器 ;
- 定義時 , 屬性僅有一個self 參數
- 調用時 , 無需括號
方法 : foo_obj.func()
屬性 : foo_obj.prop
註意 : 屬性存在意義是 : 訪問屬性是可以制造出和訪問字段完全相同的假象
屬性由方法變種而來 , 如果Python中沒有屬性 , 方法完全可以代替其功能
實例 : 對於主機列表頁面, 每次請求不可能把數據庫中的所有內容都顯示帶頁面上 , 而是通過分頁的功能局部顯示, 所以在向數據庫中請求數據時要顯示的指定獲取從第M條到第N條的所有數據 (即 : limit m, n) , 這個分頁的功能包括 :
- 根據用戶請求的當前頁總數據條數計算出 M 和 N
- 根據 M 和 N 去數據庫中請求數據
1 class Pagenation: 2 ‘‘‘ 3 分頁處理代碼 4 ‘‘‘ 5 def __init__(self,data_list, page,per_page_num = 10): 6 ‘‘‘ 7 初始化 8 :param data_list: 所有數據 9 :param page: 第幾頁 10 :param per_page_num: 每頁顯示幾條數據 11 ‘‘‘ 12 self.data_list = data_list 13 self.page = page 14 self.per_page_num = per_page_num 15 @property 16 def start(self): 17 """ 18 計算起始頁 19 :return: 20 """ 21 return (self.page - 1) * self.per_page_num 22 @property 23 def end(self): 24 """ 25 計算結尾頁 26 :return: 27 """ 28 return self.page * self.per_page_num 29 30 def show(self): 31 """ 32 打印當前頁面 33 :return: 34 """ 35 ret = self.data_list[self.start:self.end] 36 for i in ret : 37 print(i) 38 39 40 data_list = [] 41 for i in range(1,10001): 42 data_list.append("皇家%s號" % i) 43 # obj = Pagenation(data_list) 44 while True: 45 page = int(input("請輸入你查看的頁數:")) 46 obj = Pagenation(data_list,page) 47 obj.show()打印頁面
從上述可見 , Python的屬性的功能是: 屬性內部進行一系列的邏輯計算 , 最終將計算結果返回
屬性的兩種定義方式
- 裝飾器 即 : 再方法上應用裝飾器
- 靜態字段 即 : 在類中定義值為property 對象的靜態字
裝飾器方式:在類的普通方法上應用@property裝飾器
類成員的修飾符
類的所有成員在上一步驟中已經做了詳細的介紹 , 對於每一個類的成員而言都有兩種形式:
- 公有成員 , 在任何地方都能訪問
- 私有成員 , 只有在類的內部才能訪問
私有成員和公有成員的定義不同 : 私有成員命名時, 前兩個字符是下劃線 . (特殊成員除外 , 例如: __init__ , __call__ , __dict __ 等)
1 class C: 2 3 def __init__(self): 4 self.name = "公有字段" 5 self.__foo = "私有字段"
私有成員和公有成員的訪問限制不同 :
靜態字段
- 公有靜態字段 : 類可以訪問; 類內部可以訪問 , 派生類中可以訪問
- 私有靜態字段 : 僅類內部可以訪問
1 class C: 2 3 name = "公有靜態字段" 4 5 def func(self): 6 print C.name 7 8 class D(C): 9 10 def show(self): 11 print C.name 12 13 14 C.name # 類訪問 15 16 obj = C() 17 obj.func() # 類內部可以訪問 18 19 obj_son = D() 20 obj_son.show() # 派生類中可以訪問公有靜態字段
1 class C: 2 3 __name = "公有靜態字段" 4 5 def func(self): 6 print C.__name 7 8 class D(C): 9 10 def show(self): 11 print C.__name 12 13 14 C.__name # 類訪問 ==> 錯誤 15 16 obj = C() 17 obj.func() # 類內部可以訪問 ==> 正確 18 19 obj_son = D() 20 obj_son.show() # 派生類中可以訪問 ==> 錯誤私有靜態字段
普通字段
- 公有普通字段 : 對象可以訪問 ; 類內部可以訪問 ; 派生類中可以訪問
- 私有普通字段 : 僅類內部可訪問 ;
ps : 如果想要強制訪問私有字段 , 可以通過 [對象.__類名__私有字段段名] 訪問 ( 如: obj.__C__foo) , 不建議強制訪問私有成員 .
1 class C: 2 3 def __init__(self): 4 self.foo = "公有字段" 5 6 def func(self): 7 print self.foo # 類內部訪問 8 9 class D(C): 10 11 def show(self): 12 print self.foo # 派生類中訪問 13 14 obj = C() 15 16 obj.foo # 通過對象訪問 17 obj.func() # 類內部訪問 18 19 obj_son = D(); 20 obj_son.show() # 派生類中訪問公有字段
1 class C: 2 3 def __init__(self): 4 self.__foo = "私有字段" 5 6 def func(self): 7 print self.foo # 類內部訪問 8 9 class D(C): 10 11 def show(self): 12 print self.foo # 派生類中訪問 13 14 obj = C() 15 16 obj.__foo # 通過對象訪問 ==> 錯誤 17 obj.func() # 類內部訪問 ==> 正確 18 19 obj_son = D(); 20 obj_son.show() # 派生類中訪問 ==> 錯誤私有字段
方法 , 屬性 的訪問 和上述的方式相似 , 即私有成員只能在類的內部使用
ps : 非要訪問私有屬性的話 , 可以通過 對象.__類__屬性名
Python 面向對象的進階