HOWTO · Python
在 Python 中根據函式的字串名稱呼叫函式
它演示瞭如何在 Python 中根據函式的字串名稱呼叫函式
本頁內容
當函式名稱以字串形式傳入時,請從明確限定的允許函式集合中查找,並呼叫找到的函式物件。若要執行命令或其他由使用者選擇的動作,字典通常是最清楚的做法:可用名稱一目了然,也能避免任意輸入選到無關程式碼。
使用字典將核准的名稱對應至函式
先照常定義函式,再將接受的字串對應至這些函式物件。查找所要求的名稱,並在呼叫前確認結果可呼叫。這個範例會處理未知名稱,不會嘗試呼叫它:
提供的執行紀錄顯示,這個獨立範例已完成執行,結束代碼為 0,並印出 8。執行方式如下:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
def add(left, right):
return left + right
def multiply(left, right):
return left * right
functions = {"add": add, "multiply": multiply}
name = "add"
function = functions.get(name)
if callable(function):
print(function(5, 3))
else:
print(f"Unknown function: {name}")
8
這個對應表就是允許清單:只有加入 functions 的名稱才能被選取。若名稱不存在是預期情況,請使用 .get(),並決定應用程式要如何回報或處理未知名稱。若各函式接受的引數不同,也要驗證所選操作的引數;名稱查找成功,不代表呼叫簽章一定正確。
使用 getattr() 從物件或模組取得屬性
當字串要用來選取特定物件或模組上的屬性時,可以使用 getattr(object, name, default)。第三個引數會在該屬性不存在時提供預設值。接著請確認取得的值可呼叫:存在的屬性也可能是資料,而不是函式。
提供的執行紀錄顯示,這個範例已完成執行,結束代碼為 0,並印出 8。範例取得的是已繫結的實例方法:Python 會將 calculator 繫結至該方法,因此只需傳入方法其餘所需的引數。執行方式如下:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
class Calculator:
def add(self, left, right):
return left + right
calculator = Calculator()
name = "add"
operation = getattr(calculator, name, None)
if callable(operation):
print(operation(5, 3))
else:
print(f"No callable attribute named {name}")
8
匯入 math 後,也可以對模組物件使用相同模式,例如 getattr(math, name, None)。在實例上查找實例方法會取得已繫結的方法;在類別上查找則會取得未繫結函式,呼叫時必須將實例作為引數傳入。若字串來自程式碼外部,請限制可查找的來源物件及允許的屬性名稱。
僅在明確需要該命名空間時使用 globals() 和 locals()
globals() 會傳回目前模組的全域命名空間,不會傳回區域變數。若函式有意定義在該模組中,全域查找便可能合用。提供的執行紀錄顯示,這個範例已完成執行,結束代碼為 0,並印出 8。執行方式如下:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
def add(left, right):
return left + right
name = "add"
function = globals().get(name)
if callable(function):
print(function(5, 3))
else:
print(f"Unknown global function: {name}")
8
locals() 會參照呼叫當下的區域命名空間。在函式內使用時,它可以取得該函式的區域名稱;它不會檢查呼叫端的區域變數,也不會在整個程式中普遍搜尋。它的行為取決於作用域,因此作為分派器通常不如明確對應表清楚。若要了解字典,請參閱 Python 字典教學。
為何 eval() 不適合用於函式查找
eval() 會評估 Python 運算式,而不只是查找一個核准的函式名稱。例如,eval("add(5, 3)") 會剖析並評估呼叫運算式,使用評估環境中可用的名稱。若運算式含有不受信任的輸入,評估時可能會以 Python 程序的權限執行程式碼。請勿使用 eval() 分派由使用者、檔案、網路請求或其他不受信任來源提供的名稱。
若運算式確實來自可信且受控的來源,Python 文件說明了 eval() 的行為與命名空間參數。一般的函式選擇使用字典允許清單更簡單,也能限制輸入可選取的項目。剖析或驗證文字,並不會讓任意評估成為明確列出操作的安全替代方案。
選擇符合輸入情況的查找方式
若要明確限定可用動作,尤其名稱由使用者或外部來源提供時,請使用字典。若物件或模組已選定,而字串用來選取其中一個屬性,請使用 getattr();同時檢查預設值與可呼叫性,並留意方法繫結。只有在確實需要模組層級查找時才使用 globals()。只有在程式刻意需要目前區域作用域中的名稱時才使用 locals(),不要將它當成通用分派器。若輸入並非完全可信,請避免以 eval() 查找名稱。
每種方式都應將查找與呼叫視為兩個不同決策:先限制可選取的可呼叫物件,再傳入符合其介面的引數。對固定的一組命令來說,這樣能讓行為更容易檢查與維護。