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删除不需要的python文件方法
Apr 24 Python
10个Python小技巧你值得拥有
Sep 29 Python
Python批处理更改文件名os.rename的方法
Oct 26 Python
python中必要的名词解释
Nov 20 Python
关于python中plt.hist参数的使用详解
Nov 28 Python
python GUI库图形界面开发之PyQt5工具栏控件QToolBar的详细使用方法与实例
Feb 28 Python
python3 实现口罩抽签的功能
Mar 11 Python
Python爬虫实例——爬取美团美食数据
Jul 15 Python
安装pyecharts1.8.0版本后导入pyecharts模块绘图时报错: “所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 ”的解决方法
Aug 18 Python
Python实现生活常识解答机器人
Jun 28 Python
Python Matplotlib绘制两个Y轴图像
Apr 13 Python
python读取并查看npz/npy文件数据以及数据显示方法
Apr 14 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
深入PHP与浏览器缓存的分析
2013/06/03 PHP
PHP版本如何选择?应该使用哪个版本?
2015/05/13 PHP
PHP实现文件上传和多文件上传
2015/12/24 PHP
网络图片延迟加载实现代码 超越jquery控件
2010/03/27 Javascript
jQuery-serialize()输出序列化form表单值的方法
2012/12/26 Javascript
js获取height和width的方法说明
2013/01/06 Javascript
获取数组中最大最小值方法js代码(自写)
2013/08/12 Javascript
比较新旧两个数组值得增加和删除的JS代码
2013/10/30 Javascript
js 判断浏览器使用的语言示例代码
2014/03/22 Javascript
网页下载文件期间如何防止用户对网页进行其他操作
2014/06/27 Javascript
加随机数引入脚本不让浏览器读取缓存
2014/09/04 Javascript
JS中JSON对象和String之间的互转及处理技巧
2016/04/06 Javascript
JavaScript中的await/async的作用和用法
2016/10/31 Javascript
vue.js学习之UI组件开发教程
2017/07/03 Javascript
underscore之Collections_动力节点Java学院整理
2017/07/10 Javascript
jsTree事件和交互以及插件plugins详解
2017/08/29 Javascript
jquery使用iscorll实现上拉、下拉加载刷新
2017/10/26 jQuery
微信小程序bindinput与bindsubmit的区别实例分析
2019/04/17 Javascript
详解vue beforeEach 死循环问题解决方法
2020/02/25 Javascript
[16:27]DOTA2 HEROS教学视频教你分分钟做大人-艾欧
2014/06/11 DOTA
[01:31]DOTA2上海特级锦标赛 SECRET战队完整宣传片
2016/03/16 DOTA
python中使用zip函数出现错误的原因
2018/09/28 Python
Python设计模式之适配器模式原理与用法详解
2019/01/15 Python
Python对接支付宝支付自实现功能
2019/10/10 Python
HTML5中Localstorage的使用教程
2015/07/09 HTML / CSS
英国汽车座椅和婴儿车购物网站:Uber Kids
2017/04/19 全球购物
Ellos瑞典官网:北欧地区时尚、美容和住宅领域领先的电子商务网站
2019/11/21 全球购物
Ticketmaster意大利:音乐会、节日、艺术和剧院的官方门票
2019/12/23 全球购物
2014年上半年工作自我评价
2014/01/18 职场文书
咖啡厅创业计划书范本
2014/01/22 职场文书
促销活动方案模板
2014/02/24 职场文书
《社戏》教学反思
2014/04/15 职场文书
高校优秀辅导员事迹材料
2014/05/07 职场文书
巴西世界杯32强口号
2014/06/05 职场文书
党员批评与自我批评发言稿
2014/10/14 职场文书
WebRTC记录音视频流(web技术分享)
2022/02/24 Javascript