python中的反射

2022-08-29 14:57:21 字數 4715 閱讀 1499

在絕大多數語言中,都有反射機制的存在。從作用上來講,反射是為了增加程式的動態描述能力。通俗一些,就是可以讓使用者參與**執行的決定權。在程式編寫的時候,我們會寫很多類,類中又有自己的函式,物件等等。這些類和函式都是為了後續**服務,程式設計師決定什麼時候用到哪乙個類,什麼時候呼叫某個函式。但很多時候,我們需要根據使用者的需求來決定執行哪一段**塊。使用者可能是通過點選,輸入資料,或者其他方式發出指令,反射則將使用者的指令傳遞到需要執行的那一段**塊。這個過程是自動執行的,無需人工去核對使用者指令是否應該執行那一段**,而是由反射機制自動查詢該執行的**塊。大多數反射都是以web來進行舉例說明,而反射本身的最常見的使用場景也確實是根據web的url不同來呼叫不同的函式。當然這裡,我們不用討論他的具體應用,只簡單說明一下他的使用意義。

python的反射機制設定較為簡單,一共有四個關鍵函式分別是getattr、hasattr、setattr、delattr。前兩個最為常用,最後乙個幾乎很少用到。python本身定義的反射是指在記憶體中對容器裡的某些元素進行操作,這個容器不僅僅包括類,還包括函式,物件,這三者不同的是在查詢物件的時候,除了會查詢物件自身,還會去建立物件的類裡面進行查詢。要用實際例子來說明一下python中的反射具體作用,先看一下需求。所有的語言中,我們都可以輕易辦到讓使用者自由輸入乙個資料,然後列印那個資料,這是最簡單的人機互動。在**裡的實現過程是,生成乙個變數,獲取使用者輸入資料,賦值給變數。列印變數。同理我們可以在某個類中定義兩個函式,然後要求使用者輸入資料,根據使用者輸入的資料來決定具體執行哪乙個函式,這就是乙個人工的反射機制。當需要查詢的函式只有兩條的時候,我們可以用if——else進行判斷。但如果資料達數百條之多,那重複性使用if不僅效率低下,而且**量也難以估量。這種情況,就需要用到反射。具體**如下:

#新建乙個方法類 命名為echo_test 類中**如下,定義三個函式,函式內容為列印函式名

__author__ = "lixin"

def echo_test1():

print("echo_test1")

def echo_test2():

print("echo_test2")

def echo_test3():

print("echo_test3")

#另乙個執行類 **如下

__author__ = "lixin" #

import echo_test 匯入方法類

func_name = input("what do you want to do?,please enter:")#請求使用者輸入資料

func = getattr(echo_test,func_name)#呼叫getattr函式,引數分別是方法類的類名,使用者輸入的資料。生成變數接收返回引數

func()#把變數當做方法執行

#輸出結果如下

/library/frameworks/python.framework/versions/3.5/bin/python3.5 /users/penglong/documents/python/s11/day8/echo_example/echo_func.py

what do you want to do?,please enter:echo_test1#輸入資料

echo_test1#執行結果

process finished with exit code 0

來分析一下**,首先說**僅做例項,極為不完善,且輸入資料只能是定義的函式的名稱,但我們主要是討論getattr的作用。從**不難看出,它接收乙個類名和乙個字串做為引數,然後去給的類裡查詢和字串相同的函式名,並將那個函式的全部內容返回。所以,我們的變數實際是乙個函式,因此可以直接呼叫。這就是乙個簡單的完整反射。也是python中反射最主要的功能。hasatter的作用更多是為了getattr服務。就如同上面的**中,有可能使用者輸入的資料,在我們的定義的函式中並沒有與之匹配的函式名,那也就無法執行。如果沒有錯誤防禦機制,程式就會崩潰,因此拿到使用者輸入的資料,在直接去查詢執行前,需要先判斷一下使用者想要執行的函式是否存在,這就是hasattr的作用了  **如下:

#在上乙份**的基礎上直接更改,注意是在互動類

func_name = input("what do you want to do?,please enter:")

func = hasattr(echo_test,func_name)#getattr改為hasatter

print(func)

輸出結果如下:

/library/frameworks/python.framework/versions/3.5/bin/python3.5 /users/penglong/documents/python/s11/day8/echo_example/echo_func.py

what do you want to do?,please enter:echo_test1

true #返回結果為布林值

process finished with exit code 0

以上,可以看出,hasattr函式的引數跟getattr是一樣的,接收乙個類和乙個字串,返回乙個布林值。它的作用就是檢測使用者輸入的內容是否有對應的函式存在。如果有,返回true,沒有,則false。我們則可以根據結果預防找不到函式的錯誤。因此,它和getattr常常配套使用,如果判定存在,則獲取,再執行,這樣可以保證**不會執行出錯。setattr的作用則是建立乙個物件,**如下:

#還是在原**基礎上修改 ,互動類

print(dir(echo_test))#首先輸出一下echo_test這個類的所有方法

func_name = input("what do you want to do?,please enter:")#請求使用者輸入資料

func = setattr(echo_test,func_name,lambda x:x+1)

#呼叫setattr函式,引數分別是類名,使用者輸入資料,乙個簡單函式

print(dir(echo_test))#再次列印echo_test這個類的所有方法

"""輸出結果如下

第一次列印類方法結果

['__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__',

'__package__', '__spec__', 'echo_test1', 'echo_test2', 'echo_test3']

what do you want to do?,please enter:lixin

第二次列印結果

['__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__',

'__package__', '__spec__', 'echo_test1', 'echo_test2', 'echo_test3', 'lixin']"""

從輸出結果分析,setattr函式的作用就是新建乙個物件,引數分別是新建物件所屬類的類名,新建物件的物件名,物件的值,這個值可以是字串,也可以是數字,當然也可以是乙個函式,上面**為了簡便,直接用了乙個匿名函式。最後乙個delattr則是刪除存在的函式,使用率較低,也沒什麼特別注意的地方。

在使用過程中,還需要提到的就是動態獲得類名,如上所有**中的類名,都是我們固定輸入的,在實際運用當中,這樣會使**極為不靈活。四個反射函式的第乙個引數都只接受類名,而無法接收字串。使用者直接輸入的資料,格式顯然是字串,因此無法直接使用。當然,我們可以把字串轉化成類名,但無需那麼麻煩。python有相應的應對措施,使用**如下:

#原**基礎上修改,互動類

__author__ = "lixin"

func_name = input("what do you want to do?,please enter:")#獲取使用者輸入資料

class_name,func_name = func_name.split("/")將使用者輸入資料分割,並分別賦值給兩個變數

model = __import__(class_name)#以__import__的形式匯入類名,並生成變數獲取返回值

flog = hasattr(model,func_name)#變數值可以直接當做引數傳入,在這裡驗證一下函式是否存在

if flog:#如果存在在呼叫getattr函式,如果不存在,則提示資料有誤。

func = getattr(model, func_name)

func()

else:

print("輸入有誤")

"""輸出結果如下:

/library/frameworks/python.framework/versions/3.5/bin/python3.5 /users/penglong/documents/python/s11/day8/echo_example/echo_func.py

what do you want to do?,please enter:echo_test/echo_test1#輸入內容,類名和函式名以/隔開

echo_test1

process finished with exit code 0"""

以上,就是python中反射的常用方法了,當然在最後一段**中,我們應該驗證一下類是否存在,但python中並沒有針對這個的函式了,舉例中也並未給出防禦機制,在實際使用中,肯定是不行的,因為類不存在,**也無法執行,所以也要給出相應的錯誤防禦機制。除了在類中查詢函式,反射自然也能用於在函式中查詢物件,在物件身上查詢屬性,自身方法等等。這一些操作,都是立足於記憶體上,而不是對**本身進行操作。

python 反射 python中的反射

什麼是反射?有時我們要訪問某個變數或是方法時並不知道到底有沒有這個變數或方法,所以就要做些判斷。判斷是否存在字串對應的變數及方法。我們知道訪問變數時是不能加引號的,否則會被當成字串處理。如果要通過字串找到對應的變數,那該怎麼辦呢 反射就是用於解決上面兩個問題而產生的,所謂反射,按我的理解就是反過來告...

python中的反射

反射 對於初學python可能較難理解,但反射是非常有用。試想一下,當別的程式傳入給你寫的這段 乙個變數 var math 這個變數是乙個字串,這個字串是乙個模組或者乙個模組下的某個方法,你需要通過變數來匯入此模組或者方法,如何匯入此模組或方法呢,如果直接執行 import var是會出錯的,因為v...

Python中的反射

反射在python中我們可以簡單的理解為通過字串來操作物件的屬性和方法。python中有4個與反射相關的方法 class animal object def init self,name,age self.name name self.age age an animal dog 2 判斷an物件是否...