假设模块文件名是data_used_to_test.py,放在tests文件夹下

文件夹结构如下:

  1. project
  2. |-tests
  3. |-data_used_to_test.py

文件内包含一个test_class类:

  1. class test_class():
  2. def test_func(arg):
  3. return "hello {}".format(arg)

代码全部基于 Python3.6.4

  1. 使用imp

    1. 用imp.find_module查找模块

      1. In [1]:file, pathname, description = imp.find_module('data_used_to_test', path=['tests/'])
      2. In [2]: file
      3. Out[2]: <_io.TextIOWrapper name='tests/data_used_to_test.py' mode='r' encoding='utf-8'>
      4. In [3]: pathname
      5. Out[3]: 'tests/data_used_to_test.py'
      6. In [4]: description
      7. Out[4]: ('.py', 'r', 1)
    2. 用imp.load_module将找到的模块加载到sys.modules中

      1. In [5]: mod = imp.load_module('test_load', file, pathname, description)
      2. In [6]: mod
      3. Out[6]: <module 'test_load' from 'tests/data_used_to_test.py'>

      这时候sys.modules里会多一条'test_load'的记录,值就是mod的值。

    3. 这时候就可以直接通过mod访问包内的对象了

      1. In [7]: mod.test_class().test_func('x')
      2. Out[7]: 'hello x'

      这个方法的优点是

      1. 简单,容易实现。
      2. 不用对pyc文件做特殊处理

      缺点是可定制性太低。不适合框架使用

      1. 无法动态修改模块源代码, 开放的api必须要很稳定,不会经常变动。
      2. 可以访问的对象一开始就要制定成固定名称。无法动态注册访问。
    4. 上面的问题2可以用getattr解决,让我们更进一步。

      1. In [8]: tmp = getattr(mod, 'test_class')
      2. In [9]: tmp
      3. Out[9]: test_load.test_class
      4. In [10]: tmp().test_func('l')
      5. Out[10]: 'hello l'

      这样就可以通过事先在外部模块中调用准备好的注册函数,

      把外部模块中的类或函数注册到一个全局的单例变量中,

      实现动态的模块加载和对象访问。

      但仍然无法解决问题 1.

      所以就需要另一种模块加载方法。

  2. 显式的定义一个加载函数

    1. import imp
    2. import sys
    3. def load_module(module_name, module_content):
    4. if fullname in sys.modules:
    5. return sys.modules[fullname]
    6. mod = sys.modules.setdefault(url, imp.new_module(module_name))
    7. mod.__file__ = module_name
    8. mod.__package__ = ''
    9. # if *.py
    10. code = compile(module_content, url, 'exec')
    11. # if *.pyc 有问题,我运行一直报错
    12. # code = marshal.loads(module_content[8:])
    13. exec(code, mod.__dict__)
    14. # 2的写法是 exec code in mod.__dict__
    15. # 其实就是让code在环境里运行一下,所以这里可能会有注入漏洞
    16. return mod

    这个函数接受模块的名字和源码内容,并使用 compile() 将其编译到一个代码对象中, 然后在一个新创建的模块对象的字典中来执行它。

    下面是这个函数的使用方式:

    1. In[1]: module_content = open('tests/data_used_to_test.py').read()
    2. In[2]: mod = load_module('test_import', module_content)

    后面就和 1.4 一样了。

    这样可以同时解决 1.3 中提出的两个问题。

    因为你是先将源码作为普通文件读进来的,也就可以做各种修改后再注册到sys.modules中。

    Pocsuite使用的就是这种方法。虽然我觉得他们当时可能也没太弄明白。

    当然这还是有不足的。

    1. 上面的两种方法都只支持简单的模块。并没有嵌入到通常的import语句中。并不支持更高级的结构比如包。
    2. 不够酷
  3. 自定义导入器

    PythonCookbook上给了自定义导入器的两种方式

    1. 创建一个元路径导入器
    2. 编写一个钩子直接嵌入到 sys.path 变量中去

    还没看明白,PEP302的文档太长了,大概知道是继承importlib.abc来做的。

Python 动态从文件中导入类或函数的方法的更多相关文章

  1. 在无代码文件的aspx文件中添加类、函数和字段的方法

    大家都知道,在开始WebForm程序时,一个WebForm由.cs代码文件与.aspx页面文件组成.在aspx文件中可以嵌入C#代码,但无法在aspx的嵌入C#代码中定义类,函数和字段等.这样,就限制 ...

  2. python中一个py文件如何调用其他py文件中的类和函数

    HelloWorld  文件名称  Hello是类 from HelloWorld import Hello >>> h = Hello() >>> h.hello ...

  3. python调用另一个.py文件中的类和函数

    同一文件夹下的调用 1.调用函数 A.py文件如下:def add(x,y):    print('和为:%d'%(x+y)) 在B.py文件中调用A.py的add函数如下: import AA.ad ...

  4. Js文件中调用其它Js函数的方法

    在项目开发过程中,也许你会遇这样的情况.在某一Js文件中需要完成某一功能,但这一功能的大部分代码在另外一个Js文件中已经完成了,自己只需要调用这个方法再加上几句代码就可以实现所需的功能.我们知道,在h ...

  5. python 一个.py文件如何调用另一个.py文件中的类和函数

    原文地址https://blog.csdn.net/winycg/article/details/78512300 在同一个文件夹下 调用函数:

  6. 使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form

    使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form 开发环境: Wing IDE 6.1 步骤1: 打开 Wing IDE,创建一个新的 pr ...

  7. 使用Python从PDF文件中提取数据

    前言 数据是数据科学中任何分析的关键,大多数分析中最常用的数据集类型是存储在逗号分隔值(csv)表中的干净数据.然而,由于可移植文档格式(pdf)文件是最常用的文件格式之一,因此每个数据科学家都应该了 ...

  8. python操作txt文件中数据教程[4]-python去掉txt文件行尾换行

    python操作txt文件中数据教程[4]-python去掉txt文件行尾换行 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文章 python操作txt文件中数据教程[1]-使用pyt ...

  9. python操作txt文件中数据教程[3]-python读取文件夹中所有txt文件并将数据转为csv文件

    python操作txt文件中数据教程[3]-python读取文件夹中所有txt文件并将数据转为csv文件 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 python操作txt文件中 ...

随机推荐

  1. Vue 项目 在局域网内访问

    之前在百度上看到过很多中  关于局域网访问项目的方法, 在这里,个人推荐两种比较喜欢的方法 一.直接在项目的package.json文件中进行配置 ,代码如下 "scripts": ...

  2. mybatis源码探索笔记-4(缓存原理)

    前言 mybatis的缓存大家都知道分为一级和二级缓存,一级缓存系统默认使用,二级缓存默认开启,但具体用的时候需要我们自己手动配置.我们依旧还是先看一个demo.这儿只贴出关键代码 public in ...

  3. rem在三星s5部分机型情况下 设置的字体大小与手机实际字体大小不一致问题

    rem在三星s5部分机型情况下 设置的字体大小与手机实际字体大小不一致问题 判断是特殊机型,做特殊处理. var u=navigator.userAgent; if($(window).width() ...

  4. python浅谈编程规范和软件开发目录规范的重要性

    前言 我们这些初学者,目前要做的就是遵守代码规范,这是最基本的,而且每个团队的规范可能还不一样,以后工作了,尽可能和团队保持一致,目前初学者就按照官方的要求即可 新人进入一个企业,不会接触到核心的架构 ...

  5. 计算机网络 - TCP/IP模型

    图片来自网上资料

  6. Python实现一个LRU

    class Node: key = None value = None pre = None next = None def __init__(self, key, value): self.key ...

  7. word2vec生成后缀名model文件处理

    引入from gensim.models import word2vec 读取test02.model里面的词· model = word2vec.Word2Vec.load('test02.mode ...

  8. 执行脚本,且以脚本名保存log

    !/bin/bash path="/sys/devices/platform/soc/fd880000.i2c-pld/i2c-0/i2c-4/i2c-15/15-0060" f_ ...

  9. 从零构建以太坊(Ethereum)智能合约到项目实战——第23章 从零构建和部署去中心化投票App,decentralization Voting Dapp

    P90 .1-从零构建和部署去中心化投票App-01 P91 .2-从零构建和部署去中心化投票App-02 P92 .3-从零构建和部署去中心化投票App-03 参考博文:http://liyuech ...

  10. log4j 日志配置

    参考:https://blog.csdn.net/x6582026/article/details/52179817/ 1.引入jar包 log4j-1.2.17.jar log4j-core-2.1 ...