Python动态导入模块和反射机制详解


Posted in Python onFebruary 18, 2020

一、前言

何谓动态导入模块,就是说模块的导入可以根据我们的需求动态的去导入,不是像一般的在代码文件开头固定的导入所需的模块。

何谓反射机制,利用字符串的形式在模块或对象中操作(查找/获取/删除/添加)成员。

下面进入具体实例介绍环节。先创建一个示例文件example.py,简单写入几个加减乘除函数,如下,方便下文讲解使用。

flag = 1  # 此变量在介绍反射机制时会用到
 
def my_sum(a, b):
 
  return a + b
 
def my_sub(a, b):
 
  return a - b

二、动态导入模块

一般,如果我们想从其他文件引用上面的几个函数方法,都会如下使用:

import example as count
 
# 加法
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。

这样我们就实现了,动态导入一个模块,并且动态输入函数名然后执行相应方法。

不过,上面还存在一点点小问题:那就是我们的模块有可能不是在本级目录中存放着,有可能是如下图存放方式:

Python动态导入模块和反射机制详解

那怎么办呢?看下面。

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)=del x.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最后一个字符串
if hasattr(module, inp):  # 判断在commons模块中是否存在inp这个字符串
  target_func = getattr(module, inp)  # 获取inp的引用
  sum_ = target_func(2, 3)  # 执行
  print(sum_)
else:
  print("404")

更多关于Python动态导入模块和反射机制请查看下面的相关文章

Python 相关文章推荐
python基于xml parse实现解析cdatasection数据
Sep 30 Python
详解Python中映射类型(字典)操作符的概念和使用
Aug 19 Python
Python循环语句之break与continue的用法
Oct 14 Python
Python 类的继承实例详解
Mar 25 Python
Python和C/C++交互的几种方法总结
May 11 Python
python 编码规范整理
May 05 Python
python实现简单多人聊天室
Dec 11 Python
python读写csv文件实例代码
Jul 05 Python
pandas的qcut()方法详解
Jul 06 Python
pytorch使用tensorboardX进行loss可视化实例
Feb 24 Python
python如何快速拼接字符串
Oct 28 Python
Selenium执行完毕未关闭chromedriver/geckodriver进程的解决办法(java版+python版)
Dec 07 Python
pytorch进行上采样的种类实例
Feb 18 #Python
new_zeros() pytorch版本的转换方式
Feb 18 #Python
对pytorch的函数中的group参数的作用介绍
Feb 18 #Python
基于python3实现倒叙字符串
Feb 18 #Python
Python日期格式和字符串格式相互转换的方法
Feb 18 #Python
Python数组并集交集补集代码实例
Feb 18 #Python
通过python检测字符串的字母
Feb 18 #Python
You might like
通过5个php实例细致说明传值与传引用的区别
2012/08/08 PHP
php实现在新浪云中使用imagick生成缩略图并上传的方法
2016/09/26 PHP
PHP编写daemon process 实例详解
2016/11/13 PHP
利用jQuery的deferred对象实现异步按顺序加载JS文件
2013/03/17 Javascript
javascript打印大全(打印页面设置/打印预览代码)
2013/03/29 Javascript
jquery.validate的使用说明介绍
2013/11/12 Javascript
JavaScript制作的可折叠弹出式菜单示例
2014/04/04 Javascript
JavaScript对象数组如何按指定属性和排序方向进行排序
2016/06/15 Javascript
基于Bootstrap的UI扩展 StyleBootstrap
2016/06/17 Javascript
JS控制div跳转到指定的位置的几种解决方案总结
2016/11/05 Javascript
微信小程序 图片边框解决方法
2017/01/16 Javascript
js实现横向拖拽导航条功能
2017/02/17 Javascript
[js高手之路]从原型链开始图解继承到组合继承的产生详解
2017/08/28 Javascript
vue.js根据代码运行环境选择baseurl的方法
2018/02/28 Javascript
微信小程序scroll-view横向滑动嵌套for循环的示例代码
2018/09/20 Javascript
d3绘制基本的柱形图的实现代码
2018/12/12 Javascript
Vue.js样式动态绑定实现小结
2019/01/24 Javascript
一些你可能不熟悉的JS知识点总结
2019/03/15 Javascript
bootstrap datepicker的基本使用教程
2019/07/09 Javascript
element-ui 弹窗组件封装的步骤
2021/01/22 Javascript
[01:07:15]DOTA2-DPC中国联赛 正赛 DLG vs XG BO3 第二场 1月25日
2021/03/11 DOTA
python实现单线程多任务非阻塞TCP服务端
2017/06/13 Python
python 用所有标点符号分隔句子的示例
2019/07/15 Python
python使用opencv实现马赛克效果示例
2019/09/28 Python
Python urlopen()和urlretrieve()用法解析
2020/01/07 Python
巴西最大的珠宝连锁店:Vivara
2019/04/18 全球购物
遗产继承公证书
2014/04/09 职场文书
岗位竞聘演讲稿范文
2014/04/24 职场文书
求职信结尾怎么写
2014/05/26 职场文书
个人批评与自我批评发言稿
2014/09/28 职场文书
普通党员群众路线教育实践活动心得体会
2014/11/04 职场文书
2015年端午节活动方案
2015/05/05 职场文书
幼儿教师继续教育培训心得体会
2016/01/19 职场文书
Nginx反向代理及负载均衡如何实现(基于linux)
2021/03/31 Servers
Golang表示枚举类型的详细讲解
2021/09/04 Golang
Python自动化实战之接口请求的实现
2022/05/30 Python