-
問題描述
今天遇到個問題,在一個類裏面,想要通過字符串調用類裏面的方法,即(注意,以下爲錯誤代碼演示,只是爲了表述問題):
class A(object):
def a(self):
print('xxxxx')
def b(self):
c= 'a'
self.c()
test = A()
test.b()
如上面代碼所示,在b函數裏面,我將字符 a 賦值給了 c ,然後在後面,想要通過 self.c() 的方式,來替代 self.a(),完成對 a 函數的調用。當然,上面的代碼毫無疑問的報錯了,那麼,怎麼才能通過字符串調用類裏面的函數呢?
-
解決方法
首先,來解決類裏面通過字符串來調用函數的問題,其實也很簡單,我們需要用到一個稍微高階一點的Python自帶函數: getattr()
直白的說,這個函數是獲取一個實例(也可以說是類)裏面的屬性或方法。用法爲:
getattr(object, name[, default])
第一個object參數爲: 傳入一個實例或者類
第二個name參數爲: 你想要獲得的這個類或實例裏面的屬性或方法的名稱
第三個參數default爲: 如果沒有在這個類或實例裏面找到對應的屬性或方法,應該返回什麼。
如果想要詳細瞭解這個內建函數的使用方法,請看:Python getattr() 函數 | 菜鳥教程
這裏舉個例子:
class A(object):
def a(self):
print('sfsdf')
test = A()
print(getattr(test, 'a', 'None'))
print(getattr(test, 'b', 'None'))
運行結果如下:
從上面的代碼,我們可以看到,getattr()函數獲得了 test 實例裏面的 a 方法,然後將該方法打印了出來,我們還想獲取 test 實例的 b 方法, 但是 test 實例並沒有 b 方法,所以就返回了我們預先指定的 None。這就是getattr() 函數的用法。說到這裏,相信不少童鞋已經知道怎麼通過字符串調用類方法了,完整代碼如下:
class A(object):
def a(self):
print('GodLordGee')
def b(self):
c= 'a'
func = getattr(self, c, None)
func()
test = A()
test.b()
如上,我們就可以通過字符串,調用類裏面的方法了。
也許很多童鞋能夠理解這個內建函數的用法,但是卻不知道這個函數的實際使用場景,那麼我可以在這裏給你提供一個使用場景:
你寫了一個類,類裏面有很多個功能函數,還有一個主函數。在主函數裏面,會傳進來不同的字符串,這些字符串表示程序想要調用的方法。例如:主函數傳進來一個 ‘start’ 字符串,表示程序現在要調用start函數;又過了一會,主函數傳進來了一個 'pause' 字符串,表示程序現在想要調用pause函數;再過了一會,主函數傳進來了一個‘stop’ 字符串,表示程序現在想要調用stop函數。那麼,如上所述的一個過程,我們只需要一個getattr()函數,就可以很方便的調用類裏面的各種方法。
-
擴展知識
知道了如何通過字符串調用類裏面的方法,那麼,如果通過字符串直接調用方法呢?這裏有三個函數可以幫助我們實現這個功能(eval、locals、globals):
>>> def a():
print('I am a')
>>> def b():
print('I am b')
>>> eval('a')
<function a at 0x000002C526C81C80>
>>> eval('a')()
I am a
>>> eval('b')()
I am b
>>> locals()['a']()
I am a
>>> locals()['b']()
I am b
>>> globals()['a']()
I am a
>>> globals()['b']()
I am b
>>>
相信通過上面的代碼,大家已經知道如果通過字符串調用方法了。如果想要詳細瞭解上述三個函數的具體用法,請谷歌百度哦~
Tips:儘量不要使用eval函數,因爲eval is evil。使用這個函數是不安全的,自己用還好,但如果是搭建了個服務器什麼的,別有用心的人上傳上來惡意代碼,你的程序用eval一執行,那豈不是GG ?