【问题标题】:How do I unload (reload) a Python module?如何卸载(重新加载)Python 模块?
【发布时间】:2010-10-01 01:21:52
【问题描述】:

我有一个长期运行的 Python 服务器,并且希望能够在不重新启动服务器的情况下升级服务。这样做的最佳方法是什么?

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()

【问题讨论】:

  • 备忘提示:“import”不是“load”的意思,而是“如果还没有加载就加载,然后导入命名空间”。
  • 问题不应该包括“卸载”,因为这在 python 中是不可能的 - 然而,重新加载是一个已知的范例,如下所述
  • 我在 py2exe 应用程序中使用动态模块时遇到了同样的问题。由于 py2exe 始终将字节码保留在 zip 目录中,因此重新加载不起作用。但我找到了一个使用 import_file 模块的工作解决方案。现在我的应用程序运行良好。
  • 如果你想“卸载”,因为代码正在使用试图删除 .pyc 文件?

标签: python module reload python-import


【解决方案1】:

您可以使用importlib.reload() 重新加载已经导入的模块:

from importlib import reload  # Python 3.4+
import foo

while True:
    # Do some things.
    if is_changed(foo):
        foo = reload(foo)

在 Python 2 中,reload 是一个内置函数。在 Python 3 中,moved 对应于 imp 模块。在 3.4 中,impdeprecated 支持 importlib。面向 3 或更高版本时,在调用 reload 时引用相应的模块或将其导入。

我认为这就是你想要的。像 Django 的开发服务器这样的 Web 服务器使用它,这样您就可以看到代码更改的效果,而无需重新启动服务器进程本身。

引用文档:

  • 重新编译 Python 模块的代码并重新执行模块级代码,通过重用最初加载模块的 loader,定义一组新的对象,这些对象绑定到模块字典中的名称。扩展模块的init函数不会被第二次调用。
  • 与 Python 中的所有其他对象一样,旧对象仅在其引用计数降至零后才会被回收。
  • 模块命名空间中的名称已更新,以指向任何新的或更改的对象。
  • 对旧对象的其他引用(例如模块外部的名称)不会重新绑定以引用新对象,如果需要,必须在它们出现的每个命名空间中进行更新。

正如您在问题中所指出的,如果 Foo 类位于 foo 模块中,则您必须重构 Foo 对象。

【讨论】:

  • 实际上,当您更改文件时,django dev 服务器会自行重新启动..(它会重新启动服务器,而不仅仅是重新加载模块)
  • 这个“is_changed”函数从何而来?我没有看到关于它的任何文档,它不能在我的 Python 3.1.3 环境中运行,也不能在 2.6.4 中运行。
  • no cdleary,Django 不能只使用 reload:pyunit.sourceforge.net/notes/reloading.html
  • 对于具有依赖关系的模块来说,重新加载是不够的。请参阅下面的 bobince:stackoverflow.com/a/438845/456878。这曾经咬过我,浪费了整整 10 分钟。
  • @jedmao @JamesDraper 我很确定is_changed 函数只是您必须编写的任意函数;它不是内置的。例如,它可能会打开与您正在导入的模块相对应的文件,并将其与缓存版本进行比较,以查看它是否已更改。
【解决方案2】:

在 Python 3.0–3.3 中,您将使用:imp.reload(module)

BDFLanswered 这个问题。

但是,imp was deprecated in 3.4, in favour of importlib(感谢@Stefan!)。

认为,因此,您现在应该使用importlib.reload(module),尽管我不确定。

【讨论】:

  • 热心的新手很高兴了解 Python 2 和 3 之间的关键细微差别。
  • @LoïcFaure-Lacroix 与 reload(__builtins__) 在 2.x 中有效的方式相同
  • @Tarrasch:这是您要重新加载的 Python 模块,就像问题中的示例一样。
  • @LoïcFaure-Lacroix 是的,小鬼可以自己重新加载。
  • @PaulD.Waite,可以确认这在 Python 3.6.5 中有效
【解决方案3】:

如果模块不是纯 Python,则删除它可能特别困难。

这里有一些信息来自:How do I really delete an imported module?

您可以使用 sys.getrefcount() 找出实际数量 参考文献。

>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3

大于 3 的数字表示 很难摆脱 模块。国产“空” (不包含任何内容)模块应该是 之后收集的垃圾

>>> del sys.modules["empty"]
>>> del empty

因为第三个参考是一个工件 getrefcount() 函数。

【讨论】:

  • 我刚刚发现如果模块是包的一部分,你也必须在那里删除它:setattr(package, "empty", None)
  • 这是正确的解决方案,特别是如果您有一个包含嵌套模块的包。 reload() 只重新加载最顶层的模块,除非您先从 sys.modules 中删除它,否则不会重新加载其中的任何内容。
【解决方案4】:

reload(module),但前提是它完全独立。如果其他任何东西都引用了该模块(或属于该模块的任何对象),那么您将得到由旧代码比您预期的更长的时间引起的微妙和奇怪的错误,并且像 isinstance 这样的东西不能在不同的地方工作相同代码的版本。

如果你有单向依赖,你还必须重新加载依赖于重新加载模块的所有模块,以摆脱对旧代码的所有引用。然后递归地重新加载依赖于重新加载的模块的模块。

如果你有循环依赖,这很常见,例如当你处理重新加载一个包时,你必须一次性卸载组中的所有模块。 reload() 不能这样做,因为它会在其依赖项被刷新之前重新导入每个模块,从而允许旧引用潜入新模块。

在这种情况下,唯一的方法是破解sys.modules,这是不受支持的。您必须检查并删除您希望在下次导入时重新加载的每个 sys.modules 条目,并删除值为 None 的条目以处理与缓存失败的相对导入有关的实现问题。这不是非常好,但只要你有一组完全独立的依赖项,不会将引用留在其代码库之外,它是可行的。

最好重新启动服务器。 :-)

【讨论】:

  • dreload 不是专门针对那个场景的吗?
  • @Josh:不,它用于重新加载包树,即使这样它也只有在包没有外部/循环依赖时才有效。
  • 您能否详细说明带有None 值的部分,因为我正好遇到了这个问题:我正在从sys.modules 中删除项目,重新导入后,一些导入的依赖项是None
  • @shclamar:背景见stackoverflow.com/questions/1958417/…(以及那里的链接)。我不清楚(甚至查看 import.c 代码)None 条目是如何在“真实”条目被删除时设法通过导入机制返回的,而且我似乎无法让它发生在2.7;将来肯定不再是问题,因为隐含的相对进口已经消失。与此同时,删除所有带有None 值的条目似乎可以解决这个问题。
  • @Eliethesaiyan:你是说reload函数吗?它是内置的,您不必导入任何库。
【解决方案5】:

对于 Python 2 使用内置函数reload

reload(module)

对于 Python 2 Python 3.23.3使用reload from module imp

import imp
imp.reload(module)

对于 Python ≥3.4imp is deprecated 支持 importlib,所以使用这个:

import importlib
importlib.reload(module)

或:

from importlib import reload
reload(module)

TL;DR:

Python ≥ 3.4:importlib.reload(module)
Python 3.2 — 3.3:imp.reload(module)
Python 2:reload(module)

【讨论】:

  • 处理以下任何情况:from six import reload_module(当然首先需要pip install six
  • @Anentropic:建议使用六包,但语法是from six.moves import reload_module (doc)
【解决方案6】:
if 'myModule' in sys.modules:  
    del sys.modules["myModule"]

【讨论】:

  • +1。我的目标是在 python 中运行鼻子测试。在我加载了一个模块并重命名了一些函数之后,调用nose.run() 时旧名称仍然存在,即使在reload(my_module) %run my_module 之后也是如此。
  • 如果您的模块导入它自己的子模块,您可能也需要删除这些子模块。类似[del(sys.modules[mod] for mod in sys.modules.keys() if mod.startswith('myModule.')]
  • 我认为这不会卸载模块。在 Python 3.8 上:import sys; import json; del sys.modules['json']; print(json.dumps([1])) 和 json 模块仍在工作,即使它不再位于 sys.modules 中。
  • 是的,我注意到一个带下划线的 sys.modules['_json'] 条目,考虑到for mod in [ m for m in sys.modules if m.lstrip('_').startswith('json') ]: del sys.modules[mod]
  • 是的。即使使用更积极的簿记,删除条目及其所有依赖项也不会删除模块的功能。 before = [mod for mod in sys.modules] ; import json ; after = [mod for mod in sys.modules if mod not in before] ; for mod in [ m for m in sys.modules if m in after ]: del sys.modules[mod](代码块没有保留换行符。;表示换行符)
【解决方案7】:

以下代码允许您兼容 Python 2/3:

try:
    reload
except NameError:
    # Python 3
    from imp import reload

您可以在两个版本中将其用作reload(),这让事情变得更简单。

【讨论】:

    【解决方案8】:

    接受的答案不处理从 X 导入 Y 的情况。此代码处理它以及标准导入案例:

    def importOrReload(module_name, *names):
        import sys
    
        if module_name in sys.modules:
            reload(sys.modules[module_name])
        else:
            __import__(module_name, fromlist=names)
    
        for name in names:
            globals()[name] = getattr(sys.modules[module_name], name)
    
    # use instead of: from dfly_parser import parseMessages
    importOrReload("dfly_parser", "parseMessages")
    

    在重新加载的情况下,我们将顶级名称重新分配给存储在新重新加载的模块中的值,从而更新它们。

    【讨论】:

    • 注意到一个问题,globals() 是指您在其中定义此函数的模块,因此如果您在与您在其中调用它的模块不同的模块中定义它,则此方法不起作用。
    • 为了交互,在&gt;&gt;&gt; from X import Y重新加载后做&gt;&gt;&gt; __import__('X', fromlist='Y')
    • @BobStein-VisiBone,当fromlist='*' 时有没有办法让它工作?
    • 好问题,不知道@MikeC。顺便说一句,我倾向于停止在导入语句中几乎所有使用from。只需在代码中明确 import &lt;package&gt; 和显式 package.symbol 即可。意识到这可能并不总是可行或可取的。 (这里有一个例外:从未来导入 print_function。)
    • Mike C:对我有用的是foo = reload(foo); from foo import *
    【解决方案9】:

    如果您不是在服务器中,但正在开发并且需要经常重新加载模块,这里有一个很好的提示。

    首先,确保您使用的是来自 Jupyter Notebook 项目的出色的 IPython shell。安装 Jupyter 后,您可以使用 ipythonjupyter console 或更好的 jupyter qtconsole 启动它,这将为您提供一个漂亮的彩色控制台,并在任何操作系统中完成代码完成。

    现在在你的 shell 中,输入:

    %load_ext autoreload
    %autoreload 2
    

    现在,每次你运行你的脚本,你的模块都会被重新加载。

    除了2,还有其他options of the autoreload magic

    %autoreload
    Reload all modules (except those excluded by %aimport) automatically now.
    
    %autoreload 0
    Disable automatic reloading.
    
    %autoreload 1
    Reload all modules imported with %aimport every time before executing the Python code typed.
    
    %autoreload 2
    Reload all modules (except those excluded by %aimport) every time before
    executing the Python code typed.
    

    当然,它也适用于 Jupyter Notebook。

    【讨论】:

      【解决方案10】:

      这是重新加载模块的现代方式:

      from importlib import reload
      

      如果您想支持 3.5 之前的 Python 版本,请使用:

      from sys import version_info
      if version_info[0] < 3:
          pass # Python 2 has built in reload
      elif version_info[0] == 3 and version_info[1] <= 4:
          from imp import reload # Python 3.0 - 3.4 
      else:
          from importlib import reload # Python 3.5+
      

      这定义了一个reload 方法,可以通过模块调用来重新加载它。例如,reload(math) 将重新加载 math 模块。

      【讨论】:

      • 或者只是做from importlib import reload。然后你可以做reload(MODULE_NAME)。不需要这个函数。
      • 我相信modulereload(MODULE_NAME)reload(MODULE_NAME) 更容易解释,并且与其他函数发生冲突的可能性更低。
      • @RichieBendall 对不起,这个答案是完全错误的。 reload() 函数采用模块对象,而不是模块名称...阅读文档:docs.python.org/3/library/importlib.html#importlib.reload 我同意 @pault - 这个“作为 modulereload”是多余的。
      • 我已更改答案以反映您的意见。
      【解决方案11】:

      对于像我这样想要卸载所有模块的人(在Emacs下的Python解释器中运行时):

         for mod in sys.modules.values():
            reload(mod)
      

      更多信息在Reloading Python modules

      【讨论】:

      • 实际上这似乎不能可靠地工作(在 2.6 中),因为并非 sys.modules.values() 中的所有内容都是一个模块。例如: >>> type(sys.modules.values()[1]) 因此,如果我尝试运行该代码,它就会失败(我知道这不是一个实用的解决方案,只是指出这一点)。
      • 它甚至在早期的 python 中都不起作用 - 正如所写的那样。我不得不排除一些名字。当我将该代码移动到我的新计算机时,我会更新帖子。
      • 经过一些修改后在 Python 2.7 中运行良好:if mod and mod.__name__ != "__main__": imp.reload(mod)
      • 这对我很有效:import imp [reload(m) for m in sys.modules.values() if m and not "" in m.__name and not imp.is_builtin(m.__name__)]
      【解决方案12】:

      Enthought Traits 有一个模块可以很好地解决这个问题。 https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

      它将重新加载任何已更改的模块,并更新正在使用它的其他模块和实例化对象。它在大多数情况下不适用于__very_private__ 方法,并且可能会阻塞类继承,但它为我节省了大量时间,因为在编写 PyQt guis 或在程序中运行的东西(如 Maya)时必须重新启动主机应用程序或核弹。它可能在 20-30% 的情况下不起作用,但它仍然非常有用。

      Enthought 的包不会在文件更改时重新加载文件 - 你必须明确地调用它 - 但如果你真的需要它,这应该不难实现

      【讨论】:

        【解决方案13】:

        其他选项。看到 Python 默认 importlib.reload 只会重新导入作为参数传递的库。它不会重新加载您的 lib 导入的库。如果您更改了很多文件并且要导入一个有些复杂的包,则必须执行深度重新加载

        如果您安装了IPythonJupyter,您可以使用函数深度重新加载所有库:

        from IPython.lib.deepreload import reload as dreload
        dreload(foo)
        

        如果您没有 Jupyter,请在您的 shell 中使用以下命令安装它:

        pip3 install jupyter
        

        【讨论】:

        • importlib 中的这个 Ipython dreload 和 reload() 都向 reload() argument must be module 抱怨。我正在使用自定义函数导入,但似乎不起作用。使用内置模块确实有效。 :-( 对于我对代码所做的每一个小改动都重新加载 iPython 是浪费时间...
        【解决方案14】:

        那些使用 python 3 并从 importlib 重新加载的人。

        如果你遇到模块似乎没有重新加载的问题...那是因为它需要一些时间来重新编译 pyc(最多 60 秒)。我写这个提示只是为了你知道你是否经历过这种的问题。

        【讨论】:

          【解决方案15】:

          2018-02-01

          1. 模块foo必须提前导入成功。
          2. from importlib import reload, reload(foo)

          31.5. importlib — The implementation of import — Python 3.6.4 documentation

          【讨论】:

            【解决方案16】:

            编辑(答案 V2)

            之前的解决方案仅用于获取重置信息,但不会更改所有引用(超过reload,但少于所需)。要实际设置所有引用,我必须进入垃圾收集器,并在那里重写引用。现在它就像一个魅力!

            请注意,如果 GC 关闭,或者重新加载不受 GC 监控的数据,则此将不起作用。如果你不想搞乱 GC,原来的答案对你来说可能就足够了。

            新代码:

            import importlib
            import inspect
            import gc
            from enum import EnumMeta
            from weakref import ref
            
            
            _readonly_attrs = {'__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',
                           '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__',
                           '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
                           '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__',
                           '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__',
                           '__subclasshook__', '__weakref__', '__members__', '__mro__', '__itemsize__', '__isabstractmethod__',
                           '__basicsize__', '__base__'}
            
            
            def reset_module(module, inner_modules_also=True):
                """
                This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
                module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
                to be the reloaded-module's
                :param module: The module to reload (module reference, not the name)
                :param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
                """
            
                # For the case when the module is actually a package
                if inner_modules_also:
                    submods = {submod for _, submod in inspect.getmembers(module)
                               if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
                    for submod in submods:
                        reset_module(submod, True)
            
                # First, log all the references before reloading (because some references may be changed by the reload operation).
                module_tree = _get_tree_references_to_reset_recursively(module, module.__name__)
            
                new_module = importlib.reload(module)
                _reset_item_recursively(module, module_tree, new_module)
            
            
            def _update_referrers(item, new_item):
                refs = gc.get_referrers(item)
            
                weak_ref_item = ref(item)
                for coll in refs:
                    if type(coll) == dict:
                        enumerator = coll.keys()
                    elif type(coll) == list:
                        enumerator = range(len(coll))
                    else:
                        continue
            
                    for key in enumerator:
            
                        if weak_ref_item() is None:
                            # No refs are left in the GC
                            return
            
                        if coll[key] is weak_ref_item():
                            coll[key] = new_item
            
            def _get_tree_references_to_reset_recursively(item, module_name, grayed_out_item_ids = None):
                if grayed_out_item_ids is None:
                    grayed_out_item_ids = set()
            
                item_tree = dict()
                attr_names = set(dir(item)) - _readonly_attrs
                for sub_item_name in attr_names:
            
                    sub_item = getattr(item, sub_item_name)
                    item_tree[sub_item_name] = [sub_item, None]
            
                    try:
                        # Will work for classes and functions defined in that module.
                        mod_name = sub_item.__module__
                    except AttributeError:
                        mod_name = None
            
                    # If this item was defined within this module, deep-reset
                    if (mod_name is None) or (mod_name != module_name) or (id(sub_item) in grayed_out_item_ids) \
                            or isinstance(sub_item, EnumMeta):
                        continue
            
                    grayed_out_item_ids.add(id(sub_item))
                    item_tree[sub_item_name][1] = \
                        _get_tree_references_to_reset_recursively(sub_item, module_name, grayed_out_item_ids)
            
                return item_tree
            
            
            def _reset_item_recursively(item, item_subtree, new_item):
            
                # Set children first so we don't lose the current references.
                if item_subtree is not None:
                    for sub_item_name, (sub_item, sub_item_tree) in item_subtree.items():
            
                        try:
                            new_sub_item = getattr(new_item, sub_item_name)
                        except AttributeError:
                            # The item doesn't exist in the reloaded module. Ignore.
                            continue
            
                        try:
                            # Set the item
                            _reset_item_recursively(sub_item, sub_item_tree, new_sub_item)
                        except Exception as ex:
                            pass
            
                _update_referrers(item, new_item)
            

            原答案

            正如@bobince 的回答中所写,如果在另一个模块中已经对该模块的引用(特别是如果它是使用as 关键字如import numpy as np 导入的),则该实例不会被覆盖。

            在应用需要配置模块的“干净”状态的测试时,这对我来说是一个很大的问题,因此我编写了一个名为 reset_module 的函数,它使用 importlibreload 函数并递归覆盖所有声明的模块的属性。它已经用 Python 3.6 版本进行了测试。

            import importlib
            import inspect
            from enum import EnumMeta
            
            _readonly_attrs = {'__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',
                           '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__',
                           '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
                           '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__',
                           '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__',
                           '__subclasshook__', '__weakref__', '__members__', '__mro__', '__itemsize__', '__isabstractmethod__',
                           '__basicsize__', '__base__'}
            
            
            def reset_module(module, inner_modules_also=True):
                """
                This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
                module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
                to be the reloaded-module's
                :param module: The module to reload (module reference, not the name)
                :param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
                """
            
                new_module = importlib.reload(module)
            
                reset_items = set()
            
                # For the case when the module is actually a package
                if inner_modules_also:
                    submods = {submod for _, submod in inspect.getmembers(module)
                               if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
                    for submod in submods:
                        reset_module(submod, True)
            
                _reset_item_recursively(module, new_module, module.__name__, reset_items)
            
            
            def _reset_item_recursively(item, new_item, module_name, reset_items=None):
                if reset_items is None:
                    reset_items = set()
            
                attr_names = set(dir(item)) - _readonly_attrs
            
                for sitem_name in attr_names:
            
                    sitem = getattr(item, sitem_name)
                    new_sitem = getattr(new_item, sitem_name)
            
                    try:
                        # Set the item
                        setattr(item, sitem_name, new_sitem)
            
                        try:
                            # Will work for classes and functions defined in that module.
                            mod_name = sitem.__module__
                        except AttributeError:
                            mod_name = None
            
                        # If this item was defined within this module, deep-reset
                        if (mod_name is None) or (mod_name != module_name) or (id(sitem) in reset_items) \
                                or isinstance(sitem, EnumMeta):  # Deal with enums
                            continue
            
                        reset_items.add(id(sitem))
                        _reset_item_recursively(sitem, new_sitem, module_name, reset_items)
                    except Exception as ex:
                        raise Exception(sitem_name) from ex
            

            注意:小心使用!在非外围模块(例如,定义外部使用的类的模块)上使用这些可能会导致 Python 中的内部问题(例如酸洗/取消酸洗问题)。

            【讨论】:

              【解决方案17】:

              对于我来说,对于 Abaqus,它就是它的工作方式。 想象一下你的文件是 Class_VerticesEdges.py

              sys.path.append('D:\...\My Pythons')
              if 'Class_VerticesEdges' in sys.modules:  
                  del sys.modules['Class_VerticesEdges']
                  print 'old module Class_VerticesEdges deleted'
              from Class_VerticesEdges import *
              reload(sys.modules['Class_VerticesEdges'])
              

              【讨论】:

              【解决方案18】:

              如果您遇到以下错误,这个答案可能会帮助您获得解决方案:

              Traceback(最近一次调用最后一次):
               文件“FFFF”,第 1 行,在
              NameError: 名称 'YYYY' 未定义

              Traceback(最近一次调用最后一次):
               文件“FFFF”,第 1 行,在
               文件“/usr/local/lib/python3.7/importlib/__init__.py”,第 140 行,重新加载
                 raise TypeError("reload() 参数必须是一个模块")
              TypeError: reload() 参数必须是一个模块

              如果您有如下所示的导入,您可能需要使用sys.modules 来获取要重新加载的模块:

                import importlib
                import sys
              
                from YYYY.XXX.ZZZ import CCCC
                import AAA.BBB.CC
              
              
                def reload(full_name)
                  if full_name in sys.modules:
                    importlib.reload(sys.modules[full_name])
              
              
                reload('YYYY.XXX.ZZZ') # this is fine in both cases
                reload('AAA.BBB.CC')  
              
                importlib.reload(YYYY.XXX.ZZZ) # in my case: this fails
                importlib.reload(AAA.BBB.CC)   #             and this is ok
              
              

              主要问题是importlib.reload 只接受模块而不接受字符串。

              【讨论】:

                【解决方案19】:

                从 sys.modules 中删除模块还需要删除 'None' 类型。

                方法一:

                import sys
                import json  ##  your module
                
                for mod in [ m for m in sys.modules if m.lstrip('_').startswith('json') or sys.modules[m] == None ]: del sys.modules[mod]
                
                print( json.dumps( [1] ) )  ##  test if functionality has been removed
                

                方法2,使用簿记条目,删除所有依赖:

                import sys
                
                before_import = [mod for mod in sys.modules]
                import json  ##  your module
                after_import = [mod for mod in sys.modules if mod not in before_import]
                
                for mod in [m for m in sys.modules if m in after_import or sys.modules[m] == None]: del sys.modules[mod]
                
                print( json.dumps( [2] ) )  ##  test if functionality has been removed
                

                可选,只是为了确保所有条目都已输出,如果您选择:

                import gc
                gc.collect()
                

                【讨论】:

                  【解决方案20】:

                  另一种方法是在函数中导入模块。这样,当函数完成时,模块就会被垃圾收集。

                  【讨论】:

                  • 模块永远不会被垃圾回收,因为至少在sys.modules中保存了一个全局引用。
                  【解决方案21】:

                  我在尝试在 Sublime Text 中重新加载某些内容时遇到了很多麻烦,但最后我可以编写这个实用程序来根据 sublime_plugin.py 用于重新加载模块的代码在 Sublime Text 上重新加载模块。

                  以下内容允许您从名称上带有空格的路径重新加载模块,然后在重新加载后您可以像往常一样导入。

                  def reload_module(full_module_name):
                      """
                          Assuming the folder `full_module_name` is a folder inside some
                          folder on the python sys.path, for example, sys.path as `C:/`, and
                          you are inside the folder `C:/Path With Spaces` on the file 
                          `C:/Path With Spaces/main.py` and want to re-import some files on
                          the folder `C:/Path With Spaces/tests`
                  
                          @param full_module_name   the relative full path to the module file
                                                    you want to reload from a folder on the
                                                    python `sys.path`
                      """
                      import imp
                      import sys
                      import importlib
                  
                      if full_module_name in sys.modules:
                          module_object = sys.modules[full_module_name]
                          module_object = imp.reload( module_object )
                  
                      else:
                          importlib.import_module( full_module_name )
                  
                  def run_tests():
                      print( "\n\n" )
                      reload_module( "Path With Spaces.tests.semantic_linefeed_unit_tests" )
                      reload_module( "Path With Spaces.tests.semantic_linefeed_manual_tests" )
                  
                      from .tests import semantic_linefeed_unit_tests
                      from .tests import semantic_linefeed_manual_tests
                  
                      semantic_linefeed_unit_tests.run_unit_tests()
                      semantic_linefeed_manual_tests.run_manual_tests()
                  
                  if __name__ == "__main__":
                      run_tests()
                  

                  如果您是第一次运行,这应该会加载模块,但如果稍后您可以再次使用方法/函数run_tests(),它将重新加载测试文件。使用 Sublime Text (Python 3.3.6) 经常发生这种情况,因为它的解释器永远不会关闭(除非您重新启动 Sublime Text,即 Python3.3 解释器)。

                  【讨论】:

                    猜你喜欢
                    • 2014-03-05
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-09-08
                    • 2012-10-19
                    • 1970-01-01
                    相关资源
                    最近更新 更多