反射內建方法
阿新 • • 發佈:2022-04-17
python是動態語言,而反射(reflection)機制被視為動態語言的關鍵。
反射機制指的是在程式的執行狀態中
對於任意一個類,都可以知道這個類的所有屬性和方法;
對於任意一個物件,都能夠呼叫他的任意方法和屬性。
這種動態獲取程式資訊以及動態呼叫物件的功能稱為反射機制。
class People:
def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender obj=People('egon',18,'male') dir(obj) # 列表中檢視到的屬性全為字串 [......,'age', 'gender', 'name']
接下來就是想辦法通過字串來操作物件的屬性了,這就涉及到內建函式hasattr、getattr、setattr、delattr的使用了(Python中一切皆物件,類和物件都可以被這四個函式操作,用法一樣)
class Teacher: def __init__(self,full_name): self.full_name=full_name t=Teacher('Egon Lin') # hasattr(object,'name') hasattr(t,'full_name') # 按字串'full_name'判斷有無屬性t.full_name # getattr(object, 'name', default=None) getattr(t,'full_name',None) # 等同於t.full_name,不存在該屬性則返回預設值None # setattr(x, 'y', v) setattr(t,'age',18) # 等同於t.age=18 # delattr(x, 'y') delattr(t,'age') # 等同於del t.age
基於反射可以十分靈活地操作物件的屬性,比如將使用者互動的結果反射到具體的功能執行
>>> class FtpServer: ... def serve_forever(self): ... while True: ... inp=input('input your cmd>>: ').strip() ... cmd,file=inp.split() ... if hasattr(self,cmd): # 根據使用者輸入的cmd,判斷物件self有無對應的方法屬性 ... func=getattr(self,cmd) # 根據字串cmd,獲取物件self對應的方法屬性 ... func(file) ... def get(self,file): ... print('Downloading %s...' %file) ... def put(self,file): ... print('Uploading %s...' %file) ... >>> server=FtpServer() >>> server.serve_forever() input your cmd>>: get a.txt Downloading a.txt... input your cmd>>: put a.txt Uploading a.txt...
二、內建方法
Python的Class機制內建了很多特殊的方法來幫助使用者高度定製自己的類,這些內建方法都是以雙下劃線開頭和結尾的,會在滿足某種條件時自動觸發,我們以常用的str和del為例來簡單介紹它們的使用。
str方法會在物件被列印時自動觸發,print功能列印的就是它的返回值,我們通常基於方法來定製物件的列印資訊,該方法必須返回字串型別
>>> class People: ... def __init__(self,name,age): ... self.name=name ... self.age=age ... def __str__(self): ... return '<Name:%s Age:%s>' %(self.name,self.age) #返回型別必須是字串 ... >>> p=People('lili',18) >>> print(p) #觸發p.__str__(),拿到返回值後進行列印 <Name:lili Age:18>
del會在物件被刪除時自動觸發。由於Python自帶的垃圾回收機制會自動清理Python程式的資源,所以當一個物件只佔用應用程式級資源時,完全沒必要為物件定製del方法,但在產生一個物件的同時涉及到申請系統資源(比如系統開啟的檔案、網路連線等)的情況下,關於系統資源的回收,Python的垃圾回收機制便派不上用場了,需要我們為物件定製該方法,用來在物件被刪除時自動觸發回收系統資源的操作
class MySQL: def __init__(self,ip,port): self.conn=connect(ip,port) # 虛擬碼,發起網路連線,需要佔用系統資源 def __del__(self): self.conn.close() # 關閉網路連線,回收系統資源 obj=MySQL('127.0.0.1',3306) # 在物件obj被刪除時,自動觸發obj.__del__()
class Student: school = 'SH' def __init__(self, name): self.name = name def func(self): return self.name class Teacher(Student): def __init__(self, name, age): # super(Student, self).__init__(name) # python2中 super().__init__(name) # python3中 self.age = age def __str__(self): return self.name # 只能是字串 def __del__(self): print('deeeee') # 刪除後輸出內容 def __getattr__(self, item): print('訪問屬性不存在輸出') def __setattr__(self, key, value): # self.key = value # 會無限遞迴 self.__dict__[key] = value print('設定值的時候輸出,如果初始化中有自動設值也執行,遞迴深度一般為1000') def __call__(self, *args, **kwargs): print('物件加()呼叫時執行') """ gte 小於等於 lte 小於等於 """ obj = Teacher('cx', 18) # del obj print(obj.__dict__) obj() """ NameError SyntaxError AttributeError KeyError TypeError ZeroDivisionError """ try: print('a') # 要檢測的程式碼 except KeyError as e1: print('Key') except NameError as e2: print() except TypeError as e3: print() except Exception as e: print('其他所有錯誤在這被捕捉並執行下面程式碼') else: print('沒有錯誤則執行') # else以及以上的程式碼只會執行一種 finally: print('不管有沒有異常都會執行的程式碼') l = [1, 2, 3] if len(l) <5: raise Exception('斷言失敗') # 丟擲異常: raise Execption/TypeErroe assert len(l) == 3 # 當l長度為3是丟擲異常