Python 动态从文件中导入类或函数的方法
假设模块文件名是data_used_to_test.py,放在tests文件夹下
文件夹结构如下:
project
|-tests
|-data_used_to_test.py
文件内包含一个test_class类:
class test_class():
def test_func(arg):
return "hello {}".format(arg)
代码全部基于 Python3.6.4
使用imp
用imp.find_module查找模块
In [1]:file, pathname, description = imp.find_module('data_used_to_test', path=['tests/']) In [2]: file
Out[2]: <_io.TextIOWrapper name='tests/data_used_to_test.py' mode='r' encoding='utf-8'> In [3]: pathname
Out[3]: 'tests/data_used_to_test.py' In [4]: description
Out[4]: ('.py', 'r', 1)
用imp.load_module将找到的模块加载到sys.modules中
In [5]: mod = imp.load_module('test_load', file, pathname, description)
In [6]: mod
Out[6]: <module 'test_load' from 'tests/data_used_to_test.py'>
这时候sys.modules里会多一条'test_load'的记录,值就是mod的值。
这时候就可以直接通过mod访问包内的对象了
In [7]: mod.test_class().test_func('x')
Out[7]: 'hello x'
这个方法的优点是
- 简单,容易实现。
- 不用对pyc文件做特殊处理
缺点是可定制性太低。不适合框架使用
- 无法动态修改模块源代码, 开放的api必须要很稳定,不会经常变动。
- 可以访问的对象一开始就要制定成固定名称。无法动态注册访问。
上面的问题2可以用getattr解决,让我们更进一步。
In [8]: tmp = getattr(mod, 'test_class') In [9]: tmp
Out[9]: test_load.test_class
In [10]: tmp().test_func('l')
Out[10]: 'hello l'
这样就可以通过事先在外部模块中调用准备好的注册函数,
把外部模块中的类或函数注册到一个全局的单例变量中,
实现动态的模块加载和对象访问。
但仍然无法解决问题 1.
所以就需要另一种模块加载方法。
显式的定义一个加载函数
import imp
import sys def load_module(module_name, module_content):
if fullname in sys.modules:
return sys.modules[fullname] mod = sys.modules.setdefault(url, imp.new_module(module_name))
mod.__file__ = module_name
mod.__package__ = '' # if *.py
code = compile(module_content, url, 'exec')
# if *.pyc 有问题,我运行一直报错
# code = marshal.loads(module_content[8:]) exec(code, mod.__dict__)
# 2的写法是 exec code in mod.__dict__
# 其实就是让code在环境里运行一下,所以这里可能会有注入漏洞
return mod
这个函数接受模块的名字和源码内容,并使用 compile() 将其编译到一个代码对象中, 然后在一个新创建的模块对象的字典中来执行它。
下面是这个函数的使用方式:
In[1]: module_content = open('tests/data_used_to_test.py').read() In[2]: mod = load_module('test_import', module_content)
后面就和 1.4 一样了。
这样可以同时解决 1.3 中提出的两个问题。
因为你是先将源码作为普通文件读进来的,也就可以做各种修改后再注册到sys.modules中。
Pocsuite使用的就是这种方法。虽然我觉得他们当时可能也没太弄明白。
当然这还是有不足的。
- 上面的两种方法都只支持简单的模块。并没有嵌入到通常的import语句中。并不支持更高级的结构比如包。
- 不够酷
自定义导入器
PythonCookbook上给了自定义导入器的两种方式
- 创建一个元路径导入器
- 编写一个钩子直接嵌入到 sys.path 变量中去
还没看明白,PEP302的文档太长了,大概知道是继承importlib.abc来做的。
Python 动态从文件中导入类或函数的方法的更多相关文章
- 在无代码文件的aspx文件中添加类、函数和字段的方法
大家都知道,在开始WebForm程序时,一个WebForm由.cs代码文件与.aspx页面文件组成.在aspx文件中可以嵌入C#代码,但无法在aspx的嵌入C#代码中定义类,函数和字段等.这样,就限制 ...
- python中一个py文件如何调用其他py文件中的类和函数
HelloWorld 文件名称 Hello是类 from HelloWorld import Hello >>> h = Hello() >>> h.hello ...
- python调用另一个.py文件中的类和函数
同一文件夹下的调用 1.调用函数 A.py文件如下:def add(x,y): print('和为:%d'%(x+y)) 在B.py文件中调用A.py的add函数如下: import AA.ad ...
- Js文件中调用其它Js函数的方法
在项目开发过程中,也许你会遇这样的情况.在某一Js文件中需要完成某一功能,但这一功能的大部分代码在另外一个Js文件中已经完成了,自己只需要调用这个方法再加上几句代码就可以实现所需的功能.我们知道,在h ...
- python 一个.py文件如何调用另一个.py文件中的类和函数
原文地址https://blog.csdn.net/winycg/article/details/78512300 在同一个文件夹下 调用函数:
- 使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form
使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form 开发环境: Wing IDE 6.1 步骤1: 打开 Wing IDE,创建一个新的 pr ...
- 使用Python从PDF文件中提取数据
前言 数据是数据科学中任何分析的关键,大多数分析中最常用的数据集类型是存储在逗号分隔值(csv)表中的干净数据.然而,由于可移植文档格式(pdf)文件是最常用的文件格式之一,因此每个数据科学家都应该了 ...
- python操作txt文件中数据教程[4]-python去掉txt文件行尾换行
python操作txt文件中数据教程[4]-python去掉txt文件行尾换行 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文章 python操作txt文件中数据教程[1]-使用pyt ...
- python操作txt文件中数据教程[3]-python读取文件夹中所有txt文件并将数据转为csv文件
python操作txt文件中数据教程[3]-python读取文件夹中所有txt文件并将数据转为csv文件 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 python操作txt文件中 ...
随机推荐
- 24 JavaScript对象访问器&JavaScript对象构造器
ES5引入了Getter和Setter Getter和Setter允许定义对象访问器 JavaScript Getter(get关键字):获取对象属性 <script> var perso ...
- TomcatJVM参数优化降低内存使用率(重点)!
JVM是jdk最底层的支柱 做JVM参数优化主要是为了改善服务器性能以及内存使用率 JAVA堆分为三大部分:(新生代.老年代.永久代) ================================ ...
- [Unity] Shader Graph Error 当前渲染管道与此主节点不兼容(The current render pipeline is not compatible with this master node)
Shader Graph Error : The current render pipeline is not compatible with this master node 问题产生环境: Un ...
- day04-MyBatis的缓存与懒加载
为什么会用到缓存? 为了减少与数据库链接所消耗的时间,将查询到的内容放到内存中去,下次查询直接取用就ok了. 缓存的适应场景: 1.经常查询并且不经常改变的. 2.数据的正确与否对最终结果影响不大的. ...
- springboot+mybatis多数据源
首先,既然是多数据源,那么我们就先看下数据源怎么配置的: javaconfig类似下面这样: MapperScan注解常用配置如下: basePackages:Base packages to sca ...
- Mockito 中文文档 ( 2.0.26 beta )
Mockito 中文文档 ( 2.0.26 beta ) 由于缺乏校对,难免有谬误之处,如果发现任何语句不通顺.翻译错误,都可以在github中的项目提出issue.谢谢~ Mockito框架官方地址 ...
- 通过view获取所在的viewController对象
建议写成UIView的分类,如下: .h - (UIViewController *)viewController; .m - (UIViewController *)viewController { ...
- win10上安装mysql8(installer方式)并创建用户开启远程连接
1.进去mysql官网,下载mysql安装工具: 2.运行下载的mysql-installer-community-8.0.17.0.msi,一次往下执行就好了,以下是几个注意的点: 后面还有个地方就 ...
- Python学习笔记008
while循环 while 条件 : 执行 num =1 while num<=10: print(num) num+=1 1-100偶数 方法1 num =2 while num& ...
- c++模板(翁恺c++公开课[34-35]学习笔记)
为什么要有模板(templates):当我们需要一个列表(list),列表中元素可能都为X类型也可能都为Y类型,怎么来实现呢? 定义基类?可以实现,很多情况下可能不够简明的表达设计思想 克隆代码(写一 ...