我有一个长期运行的Python服务器,希望能够在不重新启动服务器的情况下升级服务。最好的方法是什么?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
我有一个长期运行的Python服务器,希望能够在不重新启动服务器的情况下升级服务。最好的方法是什么?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
当前回答
接受的答案不处理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")
在重新加载的情况下,我们将顶级名称重新分配给新加载的模块中存储的值,从而更新这些值。
其他回答
如果一个模块不是纯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()函数的。
这是重新加载一个模块的现代方式:
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)将重载数学模块。
如果你不在服务器上,但正在开发,需要频繁地重新加载一个模块,这里有一个不错的技巧。
首先,确保您使用的是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.
当然,它也可以在木星笔记本上工作。
重新加载(模块),但前提是它是完全独立的。如果其他任何东西引用了该模块(或属于该模块的任何对象),那么您将会得到一些微妙而奇怪的错误,这些错误是由旧代码存在的时间比您预期的要长,并且像isinstance这样的错误在相同代码的不同版本之间无法工作。
如果有单向依赖关系,还必须重新加载依赖于重新加载的模块的所有模块,以消除对旧代码的所有引用。然后递归地重新加载依赖于重新加载模块的模块。
如果你有循环依赖关系,这是非常常见的,例如当你处理重新加载一个包时,你必须一次性卸载组中的所有模块。使用reload()无法做到这一点,因为它会在刷新依赖项之前重新导入每个模块,从而允许旧的引用渗透到新模块中。
在这种情况下,唯一的方法是入侵sys。模块,这是不受支持的。你必须仔细检查并删除每个系统。您希望在下次导入时重新加载的模块项,还可以删除值为None的项,以处理缓存失败的相对导入的实现问题。这并不是很好,但只要你有一个完全自包含的依赖集,并且不会在代码库之外留下引用,它就是可行的。
最好是重新启动服务器。:-)
另一种方法是在函数中导入模块。这样,当函数完成时,模块就会被垃圾收集。