一、前言
最近有個需求,想在資料庫中存入函式名的字串,通過傳遞它來控制不同函式的執行以便業務流程的控制,
簡單來說就是通過字串來直接呼叫函式,經過查閱后,發現了四種比較可行的方法
二、方法介紹
1.eval
python內置的eval函式不僅可將符合字典、串列、元祖格式的字串轉換成字典、串列和元祖 (在實際開發的時候,如果需要把json字串轉字典或串列盡量使用json.loads來轉化,詳情可查看我之前分享的博文:python處理json字串,建議使用json.loads而不是eval())
還可以直接將字串形式的代碼直接轉化成可執行的代碼!
例如如下代碼,會將print(10000)這個字串直接執行:
str1='print(10000)'
eval(str1)
輸出結果

同理,我們可以通過eval來執行一個函式
def test(x, y):
print(x + y)
eval('test(1,2)')
輸出結果

但eval是把雙刃劍,如果用戶傳遞的字串是一些能夠獲取隱秘資訊或者帶來安全問題的代碼就可能帶來極大的問題!
例如:用戶傳入了一個洗掉當前目錄所有檔案的代碼字串,那你就等著跑路吧!

因此eval雖然強大,但是也很危險!所以要慎用!!
2.locals()和globals()
locals() 和 globals() 是python的兩個內置函式,通過它們可以以字典的方式訪問區域和全域變數,
兩個函式的區別在于locals 是只讀的,不可修改,而globals可以修改,例如:
y = 1
def test():
x = 1
locals()['x'] = 2
globals()['y'] = 2
print('locals無法對變數進行修改,所以x的值還為:', x)
print('globals可以對全域變數進行修改,所以y的值被改為:', y)
test()
執行結果

原因是locals()實際上沒有回傳區域名字空間,它回傳的是一個拷貝,所以對它進行修改,修改的是拷貝,而對實際的區域名字空間中的變數值并無影響,
globals()回傳的是實際的全域名字空間,而不是一個拷貝: 與 locals 的行為完全相反,
回到主題,通過locals和globals呼叫字串來執行函式:
def test(x, y):
print(x + y)
locals()['test'](1, 2)
print("-----------------")
globals()['test'](1, 2)
執行結果

3.getattr()
getattr() 是python的內建函式,也就是我們常說的反射,
getattr(Test,'func_1') 就相當于回傳Test類中的func_1方法!
但是這里 func_1可以為變數,比如一個表示方法名字串的變數,
例如:
class Test:
def fuc_1(self, x,y):
print(x+y)
getattr(Test(), 'fuc_1')(1,2)
輸出結果

如果getattr沒有找到這個str的方法,會拋出例外,相比eval和locals()、globals()要安全一些!

4.operator模塊的methodcaller函式
operator模塊是python中的標準運算子替代函式,它提供了一套與Python的內置運算子對應的高效率函式,例如,operator.add(x, y) 與運算式 x+y 相同,
通過它來實作字串訪問函式:
from operator import methodcaller
class Test:
def func_1(self, x, y):
print("func_1")
print(x + y)
def func_2(self):
print("func_2")
methodcaller('func_1', 1, 2)(Test()) # 傳遞引數
methodcaller('func_2')(Test()) # 不傳遞引數
輸出結果

通過查看methodcaller函式的原始碼可以發現,它是對getattr進行了一層封裝

分享暫時到這里,小伙伴們點贊、收藏、評論是對我最大的支持!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/295420.html
標籤:python
