协慌网

登录 贡献 社区

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

我有一台运行时间较长的 Python 服务器,并且希望能够在不重新启动服务器的情况下升级服务。最好的方法是什么?

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

答案

您可以通过使用内置reload功能来reload已导入的模块:

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而支持importlib ,并且将reload添加到后者中。如果定位到 3 或更高版本,则在调用reload或导入它时参考相应的模块。

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

引用文档:

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

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

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

BDFL 回答了这个问题。

但是, 在 3.4 中不推荐使用imp而推荐使用importlib (感谢@Stefan! )。

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

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

以下是一些信息: 我如何真正删除导入的模块?

您可以使用 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()函数的构件。