场景:一个模块化的应用程序,它可以在运行时动态加载 .py 模块。程序员(我)希望编辑模块的代码,然后在不停止执行的情况下将其重新加载到程序中。
可以这样做吗?
我已尝试在更新的 module.py 上第二次运行导入,但未获取更改
虽然reload
确实重新加载了一个模块,但正如另一个答案所提到的,您需要采取很多预防措施才能使其顺利运行 - 对于您可能认为可以轻松运行的某些事情,就工作量而言,您会感到非常震惊实际需要。
如果您曾经使用过 form from module import afunction
,那么您几乎可以确定reload
不会工作:如果您希望做一些有用的事情,您必须从模块内部专门导入模块,而不是reload
函数、类等(否则您必须以某种方式追逐从模块中到处导入的所有点点滴滴,然后重新绑定它们中的每一个——eep;-)。请注意,无论如何我都更喜欢遵循这条规则,无论我是否打算进行任何重新加载,但是,对于重新加载,它是至关重要的。
困难的问题是:如果你在任何地方都有存在于模块先前版本中的类的实例,那么它们reload
本身绝对不会升级这些实例。 这个问题真的很难。Python Cookbook(第 2 版)中最长、最难的秘诀之一就是关于如何对模块进行编码以支持这种“实际升级现有实例的重新加载”。当然,这仅在您以 OOP 风格编程时才重要,但是......任何复杂到需要“重新加载此插件”功能的 Python 程序很可能包含大量 OOP,因此这不是一个小问题。
重新加载的文档非常完整并且确实提到了这个问题,但没有给出如何解决它的提示。 Michael Hudson 的这个食谱,来自 Python Cookbook online,更好,但这只是我们演变成印刷版(第 2 版)的开始——食谱 20.15,它的在线版本在这里(不完整,除非你注册O'Reilly 的商业在线图书服务的免费限时预览)。
reload()会做你需要的。您只需要注意重新编译时模块中执行的代码即可;如果您的模块只包含定义,这通常是最简单的。
您可能会从livecoding模块中得到一些用处。
亚历克斯和其他人的回答涵盖了一般情况。
但是,由于您正在处理的这些模块是您自己的并且您将只编辑它们,因此可以实现某种本地重新加载机制,而不是依赖内置的重新加载。您可以将模块加载器构建为加载文件、编译它并将它们评估到特定命名空间并告诉调用代码它已准备好的东西。您可以通过确保有一个合适的init
函数来正确地重新初始化模块来处理重新加载。我假设你只会编辑这些。
这有点工作,但可能很有趣,值得你花时间。