python的反射機制十分的常用,主要是字符串與模塊應用之間的連接方法。核心是將字符串轉換成可以調用模塊、模塊方法的變量。
主要包括了以下四個方法:
hasattr(obj, name, /)
Return whether the object has an attribute with the given name.
This is done by calling getattr(obj, name) and catching AttributeError.
hasattr()是檢測obj里面是否包含了name屬性(函數、方法……),hasattr()返回True或者False。
getattr(object, name[, default]) -> value
Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case.
getattr()用來調用object.name,一般可將其賦值給其他變量。default是可選項,同樣是object.name不存在的條件下,在不填的時候將返回AttributeError;如果設置了default值,則返回用戶設置的default值。
setattr(obj, name, value, /)
Sets the named attribute on the given object to the specified value.
setattr(x, 'y', v) is equivalent to “x.y = v”
setattr()設置一個obj.name = value,也就是說設置一個新的方法(函數)到對象里面。
delattr(obj, name, /)
Deletes the named attribute from the given object.
delattr(x, 'y') is equivalent to ``del x.y''
delattr()刪除obj.name,把對象里不需要的方法(屬性)去除。
設置一個十分簡單的人物屬性代碼
class role(object): def __init__(self, name, weapon, clothes, life = 100): self.name = name self.weapon = weapon self.clothes = clothes self.life = life def buy_weapon(self, weapon_name): print("%s buy a %s" %(self.name, weapon_name)) def got_headshoot(self): print("%s got headshot!" %self.name) self.live -= 50 def show_life(self): print("Life is %s" %self.life) def __del__(self): print("Game Over!") role_default = role("zzz", "AWM", "3-level") while True: command = input('action:') if hasattr(role_default, command): command_act = getattr(role_default,command) command_act() else: print('Command not exists!')
在運行的過程中,command輸入除了buy_weapon以外的字符串都是沒有問題的。
那就來找找看buy_weapon這個函數跟其他方法有什么不同呢?
原來是buy_weapon是一個帶有兩個參數的函數,包括的額外的'weapon_name'。那我們來看一下報錯信息:
TypeError: buy_weapon() missing 1 required positional argument: 'weapon_name'
跟我們猜測的一樣,果然是少了一個參數。
定位到代碼上,我們可以知道Error出現在:
command_act()
也就是command_act調用的時候缺少了參數'weapon_name',於是我們想到了一個笨拙的方法(傳參1.0):
while True: command = input('action:') if hasattr(role_default, command): command_act = getattr(role_default,command) try: command_act() except TypeError:
factor = input('Needing a extra factor:')
command_act(factor)
else: print('Command not exists!')
我們只需要簡單的添加一下try判斷,如果判斷出來TypeError就給他傳個參數就好了唄!
在代碼后期的拓展中發現,我們要傳兩個參數怎么辦??結果是我們又缺少了一個參數,那如果以后要傳三個、四個、甚至一萬個參數呢?就只能如同以下代碼一樣不停地增加try-except個數,這樣子將會大大地增加工作量。
try: command_act() except TypeError: V1 = input('Missing Variable:') try: command_act(V1) except TypeError: V2 = input('Missing Variable2:') command_act(V1,V2)
於是我們想到設置一個循環去判斷到底應該傳多少個參數進去以及把用戶輸入當作參數傳到函數:
要用到一個比較冷門的代碼用了統計函數所需參數的個數:parameter_count = command_act.__code__.co_argcount
我們在知道所需參數個數后定義一個空列表用來“裝”這些參數的值,接下來我們寫一個循環來讓用戶循環輸入所需要的參數。
接下來我們可以學到一個額外的知識,用來批量生產變量名:
names = locals()
names['v%s'%i] = input('Input Variable:')
locals()是python用來管理變量的字典,py文件中的變量名被儲存到locals()字典里作為key,值為value。
最后用到一個很重要的知識,把列表轉換成為參數傳入函數: function(*list),總體代碼如下:
class role(object): def __init__(self, name, weapon, clothes, life = 100): self.name = name self.weapon = weapon self.clothes = clothes self.life = life def buy_weapon(self, weapon_name): print("%s buy a %s" %(self.name, weapon_name)) def got_headshoot(self): print("%s got headshot!" %self.name) self.life -= 50 def fight(self,weapon,place): print("%s use %s to shoot %s" %(self.name,weapon, place)) def show_life(self): print("Life is %s" %self.life) def __del__(self): print("Game Over!") role_default = role("zzz", "AWM", "3-level") while True: command = input('action:') if hasattr(role_default, command): command_act = getattr(role_default,command) parameter_count = command_act.__code__.co_argcount
if parameter_count == 1: # self is also a parameter no need to input command_act() else: v_list = [] for i in range(1,parameter_count): parameter = input('Input Variable:') v_list.append(parameter) command_act(*v_list) else: print('Command not exists!')
該代碼就可以實現無限參數的傳入,這樣我們在不改變類里面的代碼邏輯和代碼的條件下,完成了無論類里面的函數有多少參數都可以通過用戶輸入來解決。