How do I unload (reload) a Python module?
我有一个长期运行的python服务器,希望能够在不重新启动服务器的情况下升级服务。最好的方法是什么?
1 2 3 4 | if foo.py has changed: unimport foo <-- How do I do this? import foo myfoo = foo.Foo() |
当模块已经导入时,可以使用
1 2 3 4 5 6 7 | from importlib import reload # Python 3.4+ only. import foo while True: # Do some things. if is_changed(foo): foo = reload(foo) |
在python3中,
我想这就是你想要的。像Django的开发服务器这样的Web服务器使用它,这样您就可以看到代码更改的效果,而无需重新启动服务器进程本身。
从文件中引用:
Python modules’ code is recompiled and
the module-level code reexecuted,
defining a new set of objects which
are bound to names in the module’s
dictionary. 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.
正如您在问题中提到的,如果
在python 3.0–3.3中,您将使用:
BDFL已经回答了这个问题。
但是,在3.4中,
因此,我认为你现在应该使用
如果一个模块不是纯Python,那么删除它可能会特别困难。
以下是一些信息:如何真正删除导入的模块?
You can use sys.getrefcount() to find out the actual number of
references.
1 2 3 4 5 6 7 | >>> import sys, empty, os >>> sys.getrefcount(sys) 9 >>> sys.getrefcount(os) 6 >>> sys.getrefcount(empty) 3 |
Numbers greater than 3 indicate that
it will be hard to get rid of the
module. The homegrown"empty"
(containing nothing) module should be
garbage collected after
1 2 | >>> del sys.modules["empty"] >>> del empty |
as the third reference is an artifact
of the getrefcount() function.
如果您有单向依赖项,则还必须重新加载依赖于重新加载的模块的所有模块,以除去对旧代码的所有引用。然后递归地重新加载依赖于重新加载的模块的模块。
如果您有循环依赖项,这是非常常见的,例如在处理重新加载包时,必须一次性卸载组中的所有模块。使用
在这种情况下,唯一的方法是黑客
最好重新启动服务器。-)
1 2 | if 'myModule' in sys.modules: del sys.modules["myModule"] |
对于python 2,使用内置函数reload():
1 | reload(module) |
对于python 2和3.2–3.3,使用module imp中的reload:
1 2 | import imp imp.reload(module) |
但由于版本3.4支持importlib,因此不推荐使用
1 2 | import importlib importlib.reload(module) |
或
1 2 | from importlib import reload reload(module) |
以下代码允许您与python 2/3兼容:
1 2 3 4 5 | try: reload except NameError: # Python 3 from imp import reload |
在这两个版本中,您可以将它用作
接受的答案不处理"从X导入Y"案例。此代码还处理它和标准导入案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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") |
在重新加载的情况下,我们将顶级名称重新分配给存储在新重新加载的模块中的值,该模块将更新这些值。
这是重新加载模块的现代方法:
1 | from importlib import reload |
只需键入
例如,
如果您不在服务器中,但是正在开发并需要频繁地重新加载模块,那么这里有一个很好的提示。
首先,确保你使用的是优秀的IPython外壳,来自Jupyter笔记本项目。安装jupyter之后,您可以从
现在在shell中,键入:
1 2 | %load_ext autoreload %autoreload 2 |
现在,每次运行脚本时,都会重新加载模块。
除
1 2 3 4 5 6 7 8 9 10 11 12 | %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. |
对于像我这样希望卸载所有模块的人(在Emacs下的python解释器中运行时):
1 2 | for mod in sys.modules.values(): reload(mod) |
更多信息在重新加载python模块中。
热情特性有一个模块,可以很好地解决这个问题。https://traits.readthedocs.org/en/4.3.0//u modules/traits/util/refresh.html
它将重新加载任何已更改的模块,并更新使用它的其他模块和实例对象。它在大多数情况下不适用于
Enthould的包在文件更改时不会重新加载文件—您必须明确地调用它—但如果您真的需要它,实现起来并不那么困难。
使用python 3并从importlib重新加载的用户。
如果您遇到模块似乎无法重新加载的问题…这是因为它需要一些时间来重新编译pyc(最长60秒),我编写这个提示只是为了让您知道您是否遇到过这种问题。
2018~02-01
31.5。importlib-import的实现-python 3.6.4文档
其他选择。请注意,python的默认
如果安装了IPython或Jupyter,则可以使用函数来深度重新加载所有libs:
1 2 | from IPython.lib.deepreload import reload as dreload dreload(foo) |
如果没有jupyter,请在shell中使用以下命令安装它:
1 | pip3 install jupyter |
对于我来说,Abaqus就是这样工作的。假设您的文件是class_verticesedges.py
1 2 3 4 5 6 | 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']) |
我在尝试重新加载Sublime文本中的内容时遇到了很多问题,但最终我可以编写这个实用程序,根据
下面接受您从名称上带有空格的路径重新加载模块,然后在重新加载之后,您可以像通常那样导入模块。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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(" " ) 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() |
如果您是第一次运行,那么应该加载模块,但是如果以后您可以再次使用方法/函数
另一种方法是在函数中导入模块。这样,当函数完成时,模块就会被垃圾收集。