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

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

当前回答

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

reload(module)

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

import imp
imp.reload(module)

对于Python≥3.4,imp已弃用,改用importlib,因此使用以下命令:

import importlib
importlib.reload(module)

or:

from importlib import reload
reload(module)

TL; diana:

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

其他回答

接受的答案不处理from X import 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")

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

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

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(math)将重载数学模块。

你可以使用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中,重载是内置的。在Python 3中,它被移动到imp模块。在3.4中,弃用了imp,改用了importlib。当目标为3或更高版本时,在调用reload或import时引用适当的模块。

我觉得这就是你想要的。像Django的开发服务器这样的Web服务器使用了这个功能,这样你就可以在不重启服务器进程的情况下看到代码更改的效果。

引用文件中的内容:

Python module’s code is recompiled and the module-level code re-executed, defining a new set of objects which are bound to names in the module’s dictionary by reusing the loader which originally loaded the module. The init function of extension modules is not called a second time. As with all other objects in Python the old objects are only reclaimed after their reference counts drop to zero. The names in the module namespace are updated to point to any new or changed objects. Other references to the old objects (such as names external to the module) are not rebound to refer to the new objects and must be updated in each namespace where they occur if that is desired.

正如您在问题中所指出的,如果Foo类驻留在Foo模块中,则必须重新构造Foo对象。

如果你不在服务器上,但正在开发,需要频繁地重新加载一个模块,这里有一个不错的技巧。

首先,确保您使用的是Jupyter Notebook项目中的优秀IPython shell。在安装Jupyter之后,您可以使用ipython或Jupyter控制台启动它,甚至更好的是Jupyter qtconsole,这将为您提供一个在任何操作系统中都具有代码完成功能的漂亮的彩色控制台。

现在在shell中输入:

%load_ext autoreload
%autoreload 2

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

除了2,还有其他自动重载魔法的选项:

%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.

当然,它也可以在木星笔记本上工作。

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

它将重新加载任何已更改的模块,并更新正在使用它的其他模块和实例对象。它在__very_private__方法的大多数时候都不起作用,并且可能会阻塞类继承,但它为我节省了大量的时间,使我不必在编写PyQt gui或在Maya或Nuke等程序中运行的东西时重新启动主机应用程序。它可能有20% - 30%的时间不起作用,但它仍然非常有帮助。

Enthought的包不会在文件更改时重新加载它们——您必须显式地调用它——但如果您确实需要它,实现它应该不是那么困难