Python动态导入模块和反射机制详解
一、前言
何谓动态导入模块,就是说模块的导入可以根据我们的需求动态的去导入,不是像一般的在代码文件开头固定的导入所需的模块。
何谓反射机制,利用字符串的形式在模块或对象中操作(查找/获取/删除/添加)成员。
下面进入具体实例介绍环节。先创建一个示例文件example.py,简单写入几个加减乘除函数,如下,方便下文讲解使用。
flag=1#此变量在介绍反射机制时会用到 defmy_sum(a,b): returna+b defmy_sub(a,b): returna-b
二、动态导入模块
一般,如果我们想从其他文件引用上面的几个函数方法,都会如下使用:
importexampleascount #加法 sum=count.my_sum(2,3) #减法 sub=count.my_sub(6,2) print("sum:{},sub:{}".format(sum,sub))
但现在有这样的需求,我需要动态输入一个模块名,可以随时访问到导入模块中的方法或者变量,怎么做呢?看下面。
imp=input("请输入你需要导入的模块名称:") count=__import__(imp)#这种方式就是通过输入字符串导入你想导入的模块 #加法 sum=count.my_sum(2,3) #减法 sub=count.my_sub(6,2) print("sum:{},sub:{}".format(sum,sub))
上面实现了动态输入模块名,从而使我们能够导入模块并且执行里面的函数。但是上面有一个缺点,那就是执行的函数被固定了。那么,我们能不能改进一下,动态输入函数名,并且来执行呢?看下面。
imp=input("请输入你需要导入的模块名称:") count=__import__(imp) func=input("请输入你需要使用的函数名:") f=getattr(count,func,None) #加法 sum=f(2,3) print(sum)
getattr()方法的作用是:从导入的模块中找到你需要调用的函数func,然后返回一个该函数的引用,没有找到就烦会None。
这样我们就实现了,动态导入一个模块,并且动态输入函数名然后执行相应方法。
不过,上面还存在一点点小问题:那就是我们的模块有可能不是在本级目录中存放着,有可能是如下图存放方式:
那怎么办呢?看下面。
imp=input("请输入你想导入的模块名称:") count=__import__('first_level.{}'.format(imp),fromlist=True) fun=input("请输入你想要使用的函数名:") f=getattr(count,fun,None) #加法 sum=f(2,3) print(sum)
三、反射机制(又叫python自省)
我们先来介绍python的四个内置函数:
1.getattr()
这个函数是Python自省的核心函数,具体使用上面已经介绍了,她不仅可以用于在模块中查找获取相应的方法和变量,也可以在一个对象中查找和获取相应的方法和变量,这里就不距离介绍了。
2、hasattr(object,name)
判断模块(或对象object)是否包含名为name的方法或变量(hasattr是通过调用getattr(ojbect,name)是否抛出异常来实现的)
imp=input("请输入你想导入的模块名称:") count=__import__('first_level.{}'.format(imp),fromlist=True) print(hasattr(count,"my_sum"))#判断模块count中是否存在my_sum方法,存在返回True
3、setattr(object,name,value)
这是相对应的getattr()。参数是一个对象,一个字符串和一个任意值。字符串name可以是对象(object)中一个现有的属性或一个新的属性,这个函数将值(value)赋给属性(name)的。使用示例,setattr(x,y,v)相当于x.y=v。
imp=input("请输入你想导入的模块名称:") count=__import__('first_level.{}'.format(imp),fromlist=True) setattr(count,"flag",0)#即使example模块中没有flag变量,此处也成立,没有的话相当于给模块中新增一个变量flag print(count.flag)#打印出flag的值为0
4、delattr(object,name)
与setattr()相关的一组函数。参数是由一个对象(记住!python中一切皆是对象)和一个字符串(name)组成的。name参数必须是对象属性名之一。该函数删除该对象的一个由字符串(name)指定的属性。delattr(x,y)=delx.y.
imp=input("请输入你想导入的模块名称:") count=__import__('first_level.{}'.format(imp),fromlist=True) delattr(count,"flag") print(count.flag)#此处再打印flag的值将会报错,因为上一步已经将flag属性删除了
需要注意的是getattr,hasattr,setattr,delattr函数对模块的修改都在内存中进行,并不会影响文件中真实内容。
5、基于反射机制模拟获取web框架路由的示例
需求:输入:www.xxx.com/example/my_sum,返回执行my_sum的结果。
#动态导入模块,并执行其中函数 url=input("url:") target_module=url.split('/')[-2]#分割url,取出模块名 module=__import__('first_level.'+target_module,fromlist=True) inp=url.split("/")[-1]#分割url,并取出url最后一个字符串 ifhasattr(module,inp):#判断在commons模块中是否存在inp这个字符串 target_func=getattr(module,inp)#获取inp的引用 sum_=target_func(2,3)#执行 print(sum_) else: print("404")
更多关于Python动态导入模块和反射机制请查看下面的相关文章
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。