1. 程式人生 > 實用技巧 >反射、內建方法

反射、內建方法

一 反射

python是動態語言,而反射(reflection)機制被視為動態語言的關鍵。

反射機制指的是在程式的執行狀態中

對於任意一個類,都可以知道這個類的所有屬性和方法;

對於任意一個物件,都能夠呼叫他的任意方法和屬性。

這種動態獲取程式資訊以及動態呼叫物件的功能稱為反射機制。

在python中實現反射非常簡單,在程式執行過程中,如果我們獲取一個不知道存有何種屬性的物件,若想操作其內部屬性,可以先通過內建函式dir來獲取任意一個類或者物件的屬性列表,列表中全為字串格式

>>> 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__()