Python动态导入模块import_module 和 重载reload

发表于:2022-4-15 10:01

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:yoyoketang    来源:稀土掘金

  前言
  python动态加载import_module 和 重载reload 的使用。
  python环境:V3.6.x
  import_module
  当我们在运行一段程序,根据需要动态加载一个模块,调用里面的方法时,除了平台使用的import module,也可以在代码里面用到import_module方法。
  比如我有个模块 yoyo.py,里面写了个函数:
  def fun1():
      return "hello world"
  def fun2():
      return "上海-悠悠"
  
  a.py 需要加载yoyo.py模块(2个文件在同一层级)
  import importlib
  import inspect
  # 动态导入模块
  m = importlib.import_module('yoyo')
  print(m)  # module object
  # 调用fun1
  print(m.fun1())  # hello world
  # 获取模块全部函数
  items = inspect.getmembers(m, inspect.isfunction)
  print(dict(items))
  # {'fun1': <function fun1 at 0x0000015CEAEA0DC0>, 'fun2': <function fun2 at 0x0000015CEAEEA670>}

  运行结果:
  <module 'yoyo' from 'D:\\demo\\demo\\yoyo.py'>
  hello world
  {'fun1': <function fun1 at 0x0000015CEAEA0DC0>, 'fun2': <function fun2 at 0x0000015CEAEEA670>}

  动态更新模块
  前面importlib.import_module()导入模块是没有问题的,但是如果在执行的过程中 yoyo.py 模块发生了改变,会无法加载到最新的方法。
  可以在python交互环境测试次问题。
  D:\demo\demo>python
  Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32
  Type "help", "copyright", "credits" or "license" for more information.
  >>> import importlib
  >>> m = importlib.import_module('yoyo')
  >>> m
  <module 'yoyo' from 'D:\\demo\\demo\\yoyo.py'>
  >>> m.fun1()
  'hello world'
  >>> m.fun2()
  '上海-悠悠'
  >>>

  当我在yoyo.py模块新增一个fun3()函数时,yoyo.py内容如下:
  def fun1():
      return "hello world"
  def fun2():
      return "上海-悠悠"
  def fun3():
      return "hello yoyo"

  此时继续在上面交互环境操作,调用fun3()方法:
  >>> m.fun3()
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  AttributeError: module 'yoyo' has no attribute 'fun3'
  >>>

  于是会看到新增的函数是无法调用的,因为在前面已经导入了模块,模块里面的2个函数,已经被加载进去了,后面模块更新的内容是不会自动更新的。
  那么有没什么办法,可以在新增方法后,重新让系统加载一次模块呢?这里可以用到reload() 方法,重载模块
  reload() 重载模块
  接着刚才的报错,使用reload()重载模块。
  >>> from importlib import reload
  >>> new = reload('yoyo')
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "E:\python36\lib\importlib\__init__.py", line 139, in reload
      raise TypeError("reload() argument must be a module")
  TypeError: reload() argument must be a module
  >>>

  直接写模块名称会出现报错:reload() argument must be a module
  看下reload()的相关源码说明:传的module参数必须在使用之前被成功导入过。
  def reload(module):
      """Reload the module and return it.
      The module must have been successfully imported before.
      """
      if not module or not isinstance(module, types.ModuleType):
          raise TypeError("reload() argument must be a module")
      try:
          name = module.__spec__.name
      except AttributeError:
          name = module.__name__

  module参数可以通过sys模块获取到模块对象 sys.modules['yoyo']
  >>> import sys
  >>> sys.modules['yoyo']
  <module 'yoyo' from 'D:\\demo\\demo\\yoyo.py'>
  >>> new = importlib.reload(sys.modules['yoyo'])
  >>> new.fun3()
  'hello yoyo'
  >>> new.fun1()
  'hello world'
  >>> new.fun2()
  '上海-悠悠'

  于是就可以成功调用到新增的fun3()方法。
  更新方法和删除方法
  如果更新了方法里面代码,fun3()改成返回"123456"。
  def fun3():
      return "123456"

  重新reload()后,代码也会更新。
  >>> new = importlib.reload(sys.modules['yoyo'])
  >>> new.fun3()
  '123456'

  如果把func3()删除了呢?
  >>> new = importlib.reload(sys.modules['yoyo'])
  >>> new.fun3()
  '123456'

  重新reload()后,依然可以调用到fun3()函数,被删除的方法不会剔除。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号