首页 文章

如何卸载(重新加载)Python模块?

提问于
浏览
657

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

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

18 回答

  • 6

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

    下面接受您从名称中带空格的路径重新加载模块,然后在重新加载后,您可以像往常一样导入 .

    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 解释器) .

  • 238

    对于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'])
    
  • 8

    对于Python 2,使用内置函数reload()

    reload(module)
    

    对于Python 2和3.2-3.3,请使用reload from module imp

    import imp
    imp.reload(module)
    

    imp is deprecated自版本3.4 in favor of importlib,所以使用:

    import importlib
    importlib.reload(module)
    

    要么

    from importlib import reload
    reload(module)
    
  • 595

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

  • 77

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

    from importlib import reload
    

    只需键入 reload(MODULE_NAME) ,将 MODULE_NAME 替换为要重新加载的模块的名称 .

    例如, reload(math) 将重新加载数学函数 .

  • 20
    if 'myModule' in sys.modules:  
        del sys.modules["myModule"]
    
  • 44

    其他选择 . 看到Python默认 importlib.reload 将重新导入作为参数传递的库 . 它 won't 重新加载你的lib导入的库 . 如果您更改了大量文件并且要导入一些复杂的程序包,则必须执行 deep reload .

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

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

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

    pip3 install jupyter
    
  • -1

    您可以使用reload builtin函数在已导入模块时重新加载模块:

    from importlib import reload  # Python 3.4+ only.
    import foo
    
    while True:
        # Do some things.
        if is_changed(foo):
            foo = reload(foo)
    

    在Python 3中, reload 被移动到imp模块 . 在3.4中, imp 被弃用,而importlibreload被添加到后者 . 当定位3或更高版本时,要么在调用 reload 时引用相应的模块,要么导入它 .

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

    引用文档:

    重新编译Python模块的代码并重新执行模块级代码,定义一组新的对象,这些对象绑定到模块字典中的名称 . 扩展模块的init函数不是第二次调用 . 与Python中的所有其他对象一样,只有在引用计数降为零后才会回收旧对象 . 模块命名空间中的名称将更新为指向任何新对象或已更改的对象 . 对旧对象的其他引用(例如模块外部的名称)不会反弹以引用新对象,如果需要,必须在每个命名空间中更新它们 .

    如您在问题中所述,如果 Foo 类位于 foo 模块中,则必须重建 Foo 对象 .

  • 55

    reload(module) ,但只有当's completely stand-alone. If anything else has a reference to the module (or any object belonging to the module), then you' ll因旧代码挂起而导致的细微且好奇的错误超出预期时, isinstance 之类的东西才能在同一代码的不同版本中运行 .

    如果您有单向依赖项,则还必须重新加载依赖于重新加载的模块的所有模块,以去除对旧代码的所有引用 . 然后递归地重新加载依赖于重新加载的模块的模块 .

    如果您具有循环依赖关系(例如,在处理重新加载包时非常常见),则必须一次性卸载组中的所有模块 . 您无法使用 reload() 执行此操作,因为它将在刷新依赖项之前重新导入每个模块,从而允许旧引用进入新模块 .

    在这种情况下,唯一的方法是破解 sys.modules ,这是一种不受支持的 . 您必须通过并删除下次导入时要重新加载的每个 sys.modules 条目,并删除值为 None 的条目,以处理与缓存失败的相对导入有关的实现问题 . 它将引用留在其代码库之外,它是可行的 .

    最好重启服务器 . :-)

  • 5

    接受的答案不处理来自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")
    

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

  • 0

    Enthought Traits有一个适用于此的模块 . https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

    它将重新加载已更改的任何模块,并更新正在使用它的其他模块和实例化对象 . 它在大多数情况下都不能用 __very_private__ 方法工作,并且可以阻止类继承,但它在编写PyQt guis时不必重新启动宿主应用程序,或者在Maya或Nuke等程序中运行的东西,这节省了我的时间 . . 它还没有令人难以置信的帮助 .

    Enthought的软件包在它们改变的那一刻不会重新加载文件 - 你必须明确地调用它 - 但如果你真的需要它,这应该不是那么难以实现

  • 14

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

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

  • 61

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

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

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

  • 2

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

    BDFLanswered这个问题 .

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

    因此,我认为你现在使用importlib.reload(module),虽然我不确定 .

  • 1

    对于那些想要卸载所有模块的人(当在Emacs下的Python解释器中运行时):

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

    更多信息请参见Reloading Python modules .

  • 3

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

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

    现在在shell中输入:

    %load_ext autoreload
    %autoreload 2
    

    现在, every time 您运行脚本,您的模块将被重新加载 .

    除了 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.
    
  • 2

    如果模块不是纯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()函数的工件 .

  • 10

    2018年2月1日

    • module foo 必须提前成功导入 .

    • from importlib import reloadreload(foo)

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

相关问题