这篇教程python动态加载技术解析写得很实用,希望能帮到您。
前言提到python动态加载技术,我们需要聊上几个话题: 1)反射技术 2)模块动态加载importlib 3) callback(函数名传递)--不完全算是吧动态
反射技术先说反射技术,所谓反射技术就是指的是在程序的运行状态中,对于任意一个类,都可以知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意方法和属性,增加删除方法和属性。这种动态获取程序信息以及动态调用对象的功能称为反射机制。 步骤: class Animal: def __init__(self, name, legs) -> None: self.name = name self.legs = legs def get_legs(self): return self.legs def get_name(self): return self.nameanimal = Animal('dog', 4)print(dir(animal))['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_legs', 'get_name', 'legs', 'name'] 具体一个应用场景,比如我们的testcase来自一个文本的创建的一个测试计划,其中是一个所要执行的测试用例的list ['test_test1', 'test_test2',...] 我们要执行它,比如我的测试实例是test_obj class T1: def test_test11(self): print('test11') def test_test22(self): print('test22')class Test(T1): def test_test1(self): print('test1') def test_test2(self): print('test2')test_obj = Test()for test in [ 'test_test1', 'test_test2', 'test_test11', 'test_test22']: method = getattr(test_obj, test) # 如果该函数不存在会raise exception method()# 可以修改如下test_obj = Test()for test in [ 'test_test1', 'test_test2', 'test_test11', 'test_test22']: method = getattr(test_obj, test, lambda :'donothing') # 如果不存在就运行一个匿名函数,实际就是一个默认值 method() 反射中的setattr等不在本次讨论的范畴。
模块动态加载importlib动态加载模块,可以用于,当我们已经知道我们的模块名称,在我们的目的是动态加载这些module用于运行;动态加载指在程序运行中,动态的加载模块,而不是在运行之前利用import 或from ... import 的方式加载模块的方式。 应用场景: (1) 程序在运行期间才能确定加载的模块。 (2) 在某种条件下,需要通过模块名字符串进行加载的模块。 #mymodule/mytest.pydef helloworld(): print('hello world')class MyModule: def print_hello(self): print(f'hello from {self.__class__}')# test.pyimport importlibdef import_method1(): """From module""" module = importlib.import_module('mymodule.mytest') module.helloworld() my_module_obj = module.MyModule() my_module_obj.print_hello()def import_method2(): """From file path""" file = 'mymodule/mytest.py' module_name = 'mytest' # loading module spec = importlib.util.spec_from_file_location(module_name, file) module = importlib.util.module_from_spec(spec) #execute module spec.loader.exec_module(module) # invoke methods module.helloworld() my_module = module.MyModule() my_module.print_hello() 另外一个例子,我们的module中有很多个类,相同的方法,这样我们可以批处理进行调用 # mytest/myfile.pyimport sysclass Test1: def setup(self): print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}") def teardown(self): print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}") def run(self): print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}")class Test2: def setup(self): print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}") def teardown(self): print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}") def run(self): print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}")# test.pyimport importliblibs = 'mytest.myfile'class_names = ['Test1', 'Test2']methods = ['setup', 'run', 'teardown', 'hello'] # hello不存在的my_import = importlib.import_module(libs)for cls_ in class_names: Clss = getattr(my_import, cls_) # 获取模块下的类 my_class = Clss() # 实例化 for m in methods: method = getattr(my_class, m, lambda: "DoNothing") # 获取类方法, 默认lambda为了防止函数不存在 method() # 执行方法# output mytest.myfile.Test1.setup mytest.myfile.Test1.run mytest.myfile.Test1.teardown mytest.myfile.Test2.setup mytest.myfile.Test2.run mytest.myfile.Test2.teardown 另外一种方式: 通过__import__加载 函数原型:__import__(name, globals={}, locals={}, fromlist=[], level=-1) 参数:name:模块名,包含路径 globals:全局变量,一般默认,如果设置,可设置globals() locals:局部变量,一般默认,如果设置,可设置locals() fromlist:导入的模块,及name下的模块名、函数名、类名或者全局变量名。 返回值:module对象,通过取module得属性获取模块得函数、类或者全局变量等。
# 如上代码,我们下面的方式d1 = __import__(libs)for cls_ in class_names: Clss = getattr(my_import, cls_) # 获取模块下的类 my_class = Clss() # 实例化 for m in methods: method = getattr(my_class, m, lambda: "DoNothing") # 获取类方法 method() # 执行方法 另外一种方式:通过exec进行,但是不建议用邪恶的exec import_string = "import mytest.myfile as myfile"exec(import_string )t1 = myfile.Test1()t1.setup()
callback方式(回调)说到回调不得不提python的函数其实也是一种类型 比如你可以将一个函数名给一个变量 比如最常见的匿名函数 squre = lambda x: x*xsqure(5)25 那么回调就是我们在执行一个函数时候,另外一个函数作为一个变量传入,以便对在该函数中由系统在符合你设定的条件时自动调用 |