前言:html
本篇相關內容分爲3篇多態、繼承、封裝,這篇爲第三篇 封裝。java
Content:python
- 封裝c++
1.數據封裝和私有屬性算法
2. 類變量和實例變量(對象變量)sql
3. 類屬性和實例屬性得查找順序(MRO)編程
4. 靜態方法 類方法和對象方法使用以及參數安全
5. python的接口和自省機制app
6. 上下文管理器框架
====================================
1.python的數據封裝和私有屬性
a.python的__私有屬性
python用__開頭完成私有屬性的封裝。用__開頭的屬性名或者方法就無法直接外部獲取,只有類中的公共方法才能夠訪問。
python的數據封裝和java c++這種靜態語言不一樣的是,靜態語言其實自己有private類型的。而python是用小技巧實現了這種私有屬性。
2.類變量和實例變量
a.什麼是python的類變量?
類下的變量。
class A(): aa=1
class A: aa=1 def __init__(self,x,y): self.x=x self.y=y
class Init(object): def __init__(self, v): #print("init") self.val = v #print("init:",self.val) class Add2(Init): def __init__(self, val): #print("Add2") super(Add2, self).__init__(val) #print("add2:",self.val) self.val += 2 class Mult(Init): def __init__(self, val): #print("Mult") super(Mult, self).__init__(val) #print("Mult:",self.val) self.val *= 5 class HaHa(Init): def __init__(self, val): #print("HAHA") super(HaHa, self).__init__(val) #print("Haha:",self.val) self.val /= 5 class Pro(Add2,Mult,HaHa): # pass class Incr(Pro): def __init__(self, val): super(Incr, self).__init__(val) self.val+= 1 # Incr Pro Add2 Mult HaHa Init p = Incr(5) print(p.val) c = Add2(2) print(c.val)
把代碼中的print註釋都拿掉,能夠發現整個流程爲:
4. 靜態方法 類方法和對象方法使用以及參數
a.靜態方法 staticmethod
- 靜態方法定義:
使用裝飾器@staticmethod。參數隨意,沒有「self」和「cls」參數,可是方法體中不能使用類或實例的任何屬性和方法
- 靜態方法的一些特色:
靜態方法是類中的函數,不須要實例。
靜態方法主要是用來存放邏輯性的代碼,主要是一些邏輯屬於類,可是和類自己沒有交互,即在靜態方法中,不會涉及到類中的方法和屬性的操做。
能夠理解爲將靜態方法存在此類的名稱空間中。事實上,在python引入靜態方法以前,一般是在全局名稱空間中建立函數。-
- 靜態方法調用:
例:我要在類中實現一個獲得如今時間的方法。與傳進去的任何參數都無關那種。
import time class TimeTest(object): def __init__(self, hour, minute, second): self.hour = hour self.minute = minute self.second = second @staticmethod def showTime(): return time.strftime("%H:%M:%S", time.localtime()) print(TimeTest.showTime()) t = TimeTest(2, 10, 10) nowTime = t.showTime() print(nowTime)
b.類方法
- 類方法定義:
使用裝飾器@classmethod。第一個參數必須是當前類對象,該參數名通常約定爲「cls」,經過它來傳遞類的屬性和方法(不能傳實例的屬性和方法)
- 類方法的一些特色:
將類自己做爲對象進行操做。
無論這個方式是從實例調用仍是從類調用,它都用第一個參數把類傳遞過來
- 類方法使用:
例:實現一個基類作一個有顏色屬性的抽象共性,對於實際的顏色的值須要結合實際子類傳遞的值進行匹配
class ColorTest(object): color = "color" @classmethod def value(self): return self.color class Red(ColorTest): color = "red" class Green(ColorTest): color = "green" g = Green() print(g.value()) print(Green.value())
這時候可能有人會以爲,這個跟實例方法(普通方法)不是同樣的嘛,繼承父類,而且用繼承中的知識重寫父類中的屬性或者方法?
重點就在於,若是咱們把@classmethod這個方法去掉,Green.value()這樣去調用是會報錯的。
由於須要傳遞實例參數進去,而不能直接用類調用。
c.對象方法(實例方法)
- 實例方法定義:
第一個參數必須是實例對象,該參數名通常約定爲「self」,經過它來傳遞實例的屬性和方法(也能夠傳類的屬性和方法)
- 實例方法的一些特色:
只能由類的實例來調用,就是咱們平時最經常使用的。
比較簡單,沒有特殊裝飾器,暫不舉例。
5.python的接口和自省機制
a.什麼是python的自省機制
當咱們須要實現一個通用的DBM框架時,可能須要對數據對象的字段賦值,但咱們沒法預知用到這個框架的數據對象都有些什麼字段,換言之,咱們在寫框架的時候須要經過某種機制訪問未知的屬性。
也就是說,咱們須要在不少時候去訪問python本身爲咱們作了哪些隱藏的事情,或者某個框架裏具體實現了哪些方法等。
經過python的自省機制去讓python告訴咱們,咱們查詢的對象是什麼,有哪些功能等。
b.python自省之訪問對象的屬性
例有下面這個類,而且實例化了一個a對象。
class Company(object): def __init__(self,company_name,staffs=[]): self.company_name=company_name self.staffs=staffs def add(self,staff): self.staffs.append(staff) def remove(self,staff): self.staffs.remove(staff) user_list=['tangrong1','tangrong2','tangrong3'] a=Company("aaa",user_list)
我須要去獲得類裏的一些方法和屬性:
####訪問對象的屬性 #dir() 調用這個方法將返回包含obj大多數屬性名的列表(會有一些特殊的屬性不包含在內)。obj的默認值是當前的模塊對象。 print("dir()") print(dir(Company)) print(dir(a)) #hasattr(obj,attr) 這個方法用於檢查obj是否有一個名爲attr的值的屬性,返回一個布爾值 print("hasattr()") print(hasattr(a,"add")) print(hasattr(a,"staffs")) print(hasattr(a,"a")) #getattr(obj, attr) 調用這個方法將返回obj中名爲attr值的屬性的值,例如若是attr爲'staffs',則返回obj.staffs。 print("getattr()") print(getattr(a,"add")) print(getattr(a,"staffs")) #setattr(obj, attr, val) 調用這個方法將給obj的名爲attr的值的屬性賦值爲val。例如若是attr爲'bar',則至關於obj.bar = val。 print("setattr()") print(setattr(a,"staffs",["tangrong4","tangrong5"])) print(a.staffs)
輸出爲:
dir() ##ps:能夠發現,實例和類的dir()列出來的有些不同 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'add', 'remove'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'add', 'company_name', 'remove', 'staffs']
hasattr() True True False
getattr() <bound method Company.add of <__main__.Company object at 0x000002D3172F2518>> ['tangrong1', 'tangrong2', 'tangrong3']
setattr() None ['tangrong4', 'tangrong5']
c.python自省之訪問對象的元數據
包括各類__dict__()\__doc__\__bases__等
內容比較多,可看這篇:https://www.cnblogs.com/huxi/archive/2011/01/02/1924317.html
6.上下文管理器
a.什麼是上下文管理器?
上下文管理器就是實現了上下文管理協議的對象。主要用於保存和恢復各類全局狀態,關閉文件等,上下文管理器自己就是一種裝飾器。
感受上句很像白說是否是- -。實際例就是,相似於with語句,就是遵循了上下文管理協議,才能在內部咱們看不到的地方,幫咱們完成了退出時作出關閉文件、執行自定義代碼塊的操做的。就不用咱們顯示判斷調用讀取完了就關閉文件這種操做。
with open("test/test.txt","w") as f_obj: f_obj.write("hello")
b.用with看他遵循的上下文管理協議
上下文管理協議包括兩個方法:
contextmanager.__enter__()
從該方法進入運行時上下文,並返回當前對象或者與運行時上下文相關的其餘對象。若是with語句有as關鍵詞存在,返回值會綁定在as後的變量上。
contextmanager.__exit__(exc_type, exc_val, exc_tb)
退出運行時上下文,並返回一個布爾值標示是否有須要處理的異常。若是在執行with語句體時發生異常,那退出時參數會包括異常類型、異常值、異常追蹤信息,不然,3個參數都是None。
能用with語句的對象,也是由於這個對象裏,遵循了這個協議。
with語句就是爲支持上下文管理器而存在的,使用上下文管理協議的方法包裹一個代碼塊(with語句體)的執行,併爲try...except...finally提供了一個方便使用的封裝。
咱們建立一個能支持with(上下文管理協議)的類,這個類實現了db最開始創建鏈接,退出時關閉鏈接的操做。
import sqlite3 class DataConn: def __init__(self,db_name): self.db_name = db_name def __enter__(self): self.conn = sqlite3.connect(self.db_name) return self.conn def __exit__(self,exc_type,exc_val,exc_tb): self.conn.close() if exc_val: raise if __name__ == "__main__": db = "test/test.db" with DataConn(db) as conn: cursor = conn.cursor()
c.用contextlib自定義上下文管理器
from contextlib import contextmanager @contextmanager def file_open(path): try: f_obj = open(path,"w") yield f_obj except OSError: print("We had an error!") finally: print("Closing file") f_obj.close() if __name__ == "__main__": with file_open("test/test.txt") as fobj: fobj.write("Testing context managers")
或者簡單版: