標籤:input argument 屬性 person cst error package [] value
反射機制是通過python3內建的hasattr、getattr、setattr來實現的。即根據變數名的字串形式來擷取變數名的屬性或方法。
一、通過反射查看已知對象的屬性和方法
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接收三個參數:對象,對象的屬性或方法,以及未擷取到時的預設傳回值。
class MyClass(object): country = "China" def __init__(self, name, age): self.name = name self.age = age self._gender = None def hello(self): print("I‘m {}, {}.".format(self.name, self.age)) def gender(self, gender): self._gender = gender print(self._gender)print(getattr(MyClass, "country")) # 擷取對象的靜態屬性my = MyClass("Li", 24)print(getattr(my, "name")) # 擷取執行個體的變數(屬性)getattr(my, "hello")() # 擷取並執行執行個體的方法getattr(my, "gender")("female") # 傳入參數二、通過反射擷取模組的方法 1.訪問當前模組的對象。
def func(): func.name = "Li" func.age = 24 print("I‘m {}, {}.".format(func.name, func.age))if __name__ == ‘__main__‘: import sys # 需要引入sys模組,用sys.modelus["__main__"]訪問當前模組的記憶體位址 getattr(sys.modules["__main__"], "func")() # 從模組中擷取屬性 print(getattr(func, "name")) 2.訪問其它模組的對象。
將上面的代碼儲存到test1.py檔案中,在test2.py中匯入test1.py,同樣可以訪問MyClass類。
import test1if __name__ == ‘__main__‘: MyClass = getattr(test1, "MyClass") # 這裡也可以用sys.modules["test1"]來替代test1 print(MyClass.country) my = MyClass("Li", 24) print(getattr(my, "name")) # 擷取執行個體的變數(屬性) getattr(my, "hello")() # 擷取並執行執行個體的方法 getattr(my, "gender")("female") # 傳入參數三、__import__和importlib.import_module
python3提供了一個特殊的方法:__import__(字串參數)。__import__()方法會根據參數,動態匯入同名的模組。它的功能和getattr相似。
將test2.py中的代碼改為下面兩行,即可實現同樣的功能。
module = __import__("test1")fun = getattr(module, "func")()
或者這樣寫:
import importlibmodule = importlib.import_module("test1")fun = getattr(module, "func")()
它們都是根據模組名來訪問該模組的記憶體空間,從而擷取全域變數、函數或者類等對象。
來看一段文檔介紹:
Docstring: __import__(name, globals=None, locals=None, fromlist=(), level=0) -> module Import a module. Because this function is meant for use by the Python interpreter and not for general use,
it is better to use importlib.import_module() to programmatically import a module.
# 匯入模組應該用importlib.import_module(),__import__是提供給Python解譯器使用的。
# globals和locals、level參數可以忽略。
The fromlist should be a list of names to emulate ``from name import ...‘‘, or an empty list to emulate ``import name‘‘. When importing a module from a package, note that __import__(‘A.B‘, ...) returns package A when fromlist is empty, but its submodule B when fromlist is not empty.
# fromlist是a list of names blabla。但是試了幾次,好像只能用True來設定,其它不起作用
module = __import__("test1", ) # 它相當於import test1# module = __import__("test.person", fromlist=True) # 它相當於from test import person# 從模組中匯入py檔案,test是一個package,包含__init__.py和person.py# person.py中包含MyClass類Myclass = getattr(module, "MyClass")my = Myclass("Li", 24)my.hello()
importlib的用法也相似。
import importlib# module = importlib.import_module("test1") # import test1# module = importlib.import_module("test.person", package=True) # from test import personmodule = importlib.import_module("test_outer.test.person", package=True) # from test_outer.test import personMyclass = getattr(module, "MyClass")my = Myclass("Li", 24)my.hello()四、例子 1.遍曆模組尋找所需函數。
# 檔案夾test - __init__.py - drink.py # 定義一個drink函數,列印"I‘m drinking." - person.py - say.py # 同drink.py - sleep.py # 同drink.py
person.py
import osimport importlibclass Person: def __init__(self, name): self.name = name self.modules = self.py_list() def py_list(self): pys = os.listdir(os.path.dirname(__file__)) modules = [] for py in pys: if py.endswith(".py") and not py.startswith("__"): modules.append(importlib.import_module(py.split(".")[0])) # 將多個模組全部匯入到一個list中 return modules def action(self): while True: imp = input("小明 >>> ") fun = None for module in self.modules: # 遍曆查詢module,尋找imp函數 if hasattr(module, imp): fun = getattr(module, imp) break if fun: fun() else: print("Order isn‘t correct.")if __name__ == ‘__main__‘: per = Person("Li") per.action() 2.動態匯入模組
當然,也可以根據模組名和對象名,來擷取相應的模組,並調用相應的方法。從而不必將所有的模組都匯入進來。
import importlibclass Person: def __init__(self, name): self.name = name def action(self): while True: imp = input("小明 >>> ") try: module, fun = imp.split("/") module = importlib.import_module(module,) if hasattr(module, fun): getattr(module, fun)() else: print("Order isn‘t correct.") except: print("input not correct.")if __name__ == ‘__main__‘: per = Person("Li") per.action() # 需要輸入sleep/sleep 或者drink/drink 3.setattr的使用
import importlibclass Person: def __init__(self, name): self.name = name def sleep(self): getattr(importlib.import_module("sleep"), "sleep")() def drink(self): getattr(importlib.import_module("drink"), "drink")() def fun(self, action): if hasattr(self, action): getattr(self, action) else: setattr(self, action, self.error) # 設定aciton的函數,當然可以在上面的getattr的default關鍵字中設定 getattr(self, action)() # 調用action的函數 def error(self): print("error.")if __name__ == ‘__main__‘: per = Person("Li") per.fun("wth")
python(八):反射