python动态加载技术解析

 更新时间:2023年07月10日 08:32:01   作者:祁华平  
这篇文章主要介绍了python动态加载技术解析,说简单点就是,如果开发者发现自己的代码有bug,那么他可以在不关闭原来代码的基础之上,动态替换模块替换方法一般用reload来完成,需要的朋友可以参考下

前言

提到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.name
animal = 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.py
def helloworld():
    print('hello world')
class MyModule:
    def print_hello(self):
        print(f'hello from {self.__class__}')
# test.py
import importlib
def 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.py
import sys
class 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.py
import importlib
libs = '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*x
squre(5)
25

那么回调就是我们在执行一个函数时候,另外一个函数作为一个变量传入,以便对在该函数中由系统在符合你设定的条件时自动调用

def my_function(a, b, callback_func):
        ....
        if xxx:
                callback_func(**kwargs)

 这里不给赘述了,仅仅该一个例子,比如我们在实时读取文件的时候进行查找默写匹配的

import time
import re
def follow_file_with_timeout(tailed_file,callback_func, timeout=10):
    with open(tailed_file) as file_:
        file_.seek(0,2) # Go to the end of file
        start_time = time.time()
        while time.time() - start_time < timeout:
            curr_position = file_.tell()
            line = file_.readline()
            if not line:
                file_.seek(curr_position)
                time.sleep(1)
            else:
                callback_func(line)
def my_search(line):
    if line:
        matched = re.search('Yourpatternhear', line)
        if matched:
            print(line)
follow_file_with_timeout('test.txt', my_search)

到此这篇关于浅谈一下python动态加载技术的文章就介绍到这了,更多相关python动态加载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python编程线性回归代码示例

    python编程线性回归代码示例

    这篇文章主要介绍了python编程线性回归代码示例,具有一定借鉴价值,需要的朋友可以了解下。
    2017-12-12
  • python使用matplotlib的savefig保存时图片保存不完整的问题

    python使用matplotlib的savefig保存时图片保存不完整的问题

    这篇文章主要介绍了python使用matplotlib的savefig保存时图片保存不完整的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • jupyter notebook更换皮肤主题的实现

    jupyter notebook更换皮肤主题的实现

    这篇文章主要介绍了jupyter notebook更换皮肤主题的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Python网络请求之Requests库的高级功能运用

    Python网络请求之Requests库的高级功能运用

    在这篇文章中我们将进一步深入学习Requests库的高级功能,包括处理重定向,设置超时,处理大文件以及错误和异常处理,需要的朋友可以参考下
    2023-08-08
  • Pytorch中关于BatchNorm2d的参数解释

    Pytorch中关于BatchNorm2d的参数解释

    这篇文章主要介绍了Pytorch中关于BatchNorm2d的参数解释,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • python接口调用已训练好的caffe模型测试分类方法

    python接口调用已训练好的caffe模型测试分类方法

    今天小编就为大家分享一篇python接口调用已训练好的caffe模型测试分类方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08
  • Python使用Selenium WebDriver的入门介绍及安装教程(最新推荐)

    Python使用Selenium WebDriver的入门介绍及安装教程(最新推荐)

    这篇文章主要介绍了Python使用Selenium WebDriver的入门介绍及安装教程,本文使用环境为python3.11+win10 64位+firefox浏览器,所以本文使用的浏览器驱动是Firefox的geckodriver ,如果你使用的是其他浏览器,那么选择自己对应的浏览器驱动程序即可,需要的朋友可以参考下
    2023-04-04
  • python selenium实现发送带附件的邮件代码实例

    python selenium实现发送带附件的邮件代码实例

    这篇文章主要介绍了python selenium实现发送带附件的邮件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Python基于network模块制作电影人物关系图

    Python基于network模块制作电影人物关系图

    这篇文章主要介绍了Python基于network模块制作电影人物关系图,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • python3基于OpenCV实现证件照背景替换

    python3基于OpenCV实现证件照背景替换

    这篇文章主要为大家详细介绍了python3基于OpenCV实现证件照背景替换,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07

最新评论