【问题标题】:How to de-import a Python module?如何反导入 Python 模块?
【发布时间】:2009-11-03 15:55:05
【问题描述】:

我正在编写一个应用程序,该应用程序必须从多个模块(.py 文件)中获取元数据(作者、版本..等)并显示它们。用户选择一个脚本并执行该脚本。 (可以添加新脚本并从目标文件夹中取出旧脚本,就像插件系统一样)。

首先我导入一个脚本并取出元数据,然后我继续下一步。 但我想取消导入除用户选择的模块之外的所有其他模块。

我该如何实现?

我试过这些

1. del module
2. del sys.modules['module']

后者不起作用。我尝试了#python,得到的答案是反导入模块不好,但我想知道一种干净的实现方式。任何想法/建议都会有所帮助。

【问题讨论】:

  • 没有干净的方法来反导入模块。你要做的一切都是通过黑客攻击。
  • 通过使用ast 模块而不是导入它们来解析代码来获取元数据,就像EpydocPyDoctorSphinx 等工具所做的那样。

标签: python


【解决方案1】:

我认为this post 应该可以帮助你

编辑: 为了确保此信息的可用性(以防链接失效或类似情况),我将在此处包含来自tutor mailing list 的原始消息:


2006 年 8 月 14 日,迪克·摩尔斯写道:

实际上,我的问题是,在使用 IDLE 进行一些导入后 模块和变量的初始化,如何将其返回给它 初始状态,无需关闭并重新打开它。

所以,例如在我完成之后

>>> import math, psyco
>>> a = 4**23

如何在不关闭 IDLE 的情况下清除它们? (我曾经知道怎么做,但我忘记了。)

嗨,迪克,

通常这需要从“模块注册表中删除并删除 在代码中引用它。如果你有一个 真正 很好用的模块(比如 一个将配置参数导入每个模块),那么您将拥有一个 从每个模块中删除它的附加步骤。另外,如果你有使用 “from psyco import ...”,那么您将无法释放模块并 对模块的引用很容易(是从那个模块,还是从 第三个模块?请参阅“如果偏执:下面的代码)。

下面的函数按名称从 Python 解释器中删除一个模块, “paranoid”参数是要从其他变量中删除的变量名列表 模块(据说与模块一起被删除)。非常小心 偏执的参数;如果您的 函数和类在不同的模块中命名相同。一种常见的 发生这种情况是异常的“错误”。很多图书馆都有 “catch-all”异常在模块中称为“error”。如果您还命名了您的 异常“错误”并决定将其包含在偏执列表中……那里 去很多其他异常对象。

def delete_module(modname, paranoid=None):
    from sys import modules
    try:
        thismod = modules[modname]
    except KeyError:
        raise ValueError(modname)
    these_symbols = dir(thismod)
    if paranoid:
        try:
            paranoid[:]  # sequence support
        except:
            raise ValueError('must supply a finite list for paranoid')
        else:
            these_symbols = paranoid[:]
    del modules[modname]
    for mod in modules.values():
        try:
            delattr(mod, modname)
        except AttributeError:
            pass
        if paranoid:
            for symbol in these_symbols:
                if symbol[:2] == '__':  # ignore special symbols
                    continue
                try:
                    delattr(mod, symbol)
                except AttributeError:
                    pass

那么你应该可以像这样使用它:

delete_module('psyco')

delete_module('psyco', ['Psycho', 'KillerError'])
# only delete these symbols from every other module
# (for "from psyco import Psycho, KillerError" statements)

-Arcege

【讨论】:

  • 如果链接失效了,你能总结一下这里的内容吗?
  • 感谢链接...但是除了导入之外还有其他方法可以获取元数据。
【解决方案2】:

建议:使用__import__动态导入模块

例如

module_list = ['os', 'decimal', 'random']
for module in module_list:
    x = __import__(module)
    print 'name: %s - module_obj: %s' % (x.__name__, x)

将产生:

name: os - module_obj: <module 'os' from '/usr/lib64/python2.4/os.pyc'>
name: decimal - module_obj: <module 'decimal' from '/usr/lib64/python2.4/decimal.pyc'>
name: random - module_obj: <module 'random' from '/usr/lib64/python2.4/random.pyc'>

不过,这不会真正将其从模块注册表中删除。下次导入时,它不会重新读取包/模块文件,也不会执行它。为此,您可以像这样简单地修改上面的代码 sn-p:

import sys
module_list = ['os', 'decimal', 'random', 'test1']
for module_name in module_list:
    x = __import__(module_name)
    print 'name: %s - module_obj: %s' % (x.__name__, x)
    del x
    sys.modules.pop(module_name)

【讨论】:

    【解决方案3】:

    我最近发现这篇文章 https://www.geeksforgeeks.org/reloading-modules-python/ 等用于 Python 3.4 或更高版本

    import importlib
    importlib.reload(module) 
    

    【讨论】:

      【解决方案4】:

      我知道这篇文章已经过时了,但我刚刚遇到了这个问题,并且在过去的几天里一直在努力解决这个问题。现在我得出了一个可以完美解决这个问题的结论。请看下面的示例代码:

      try:
          theMod = sys.modules['ModNeedToBeDel']   
      except:
          theMod = None
      if theMod:
          del sys.modules['ModNeedToBeDel']
      
      #The extra try/except below is because I implemented the block in a module of a sub-package; this ModNeedToBeDel in my case was imported either by the toppest level Main code, or by the other sub-package modules. That's why I need two different try/except.
      
      try:
          theMod = sys.modules['UpperFolder.ModNeedToBeDel']   
      except:
          theMod = None
      if theMod:
          del sys.modules['UpperFolder.ModNeedToBeDel']
      import ModNeedToBeDel   # or UpperFolder.ModNeedToBeDel here
      

      注意del sys.modules[theMod] 不起作用,因为它只是删除引用,而不是实际的ModNeedToBeDel

      希望这可以帮助某人,使他们不必在这个问题上挣扎几天!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-20
        • 1970-01-01
        • 1970-01-01
        • 2015-10-06
        • 2016-07-08
        • 2015-04-02
        • 2018-11-08
        相关资源
        最近更新 更多