如何编辑正在运行的 python 程序?
场景:一个模块化应用程序,在运行时动态加载 .py 模块。程序员(我)希望编辑模块的代码,然后将其重新加载到程序中,而不停止执行。
这可以做到吗?
我尝试在更新的 module.py 上第二次运行 import,但更改并未生效
scenario: a modular app that loads .py modules on the fly as it works. programmer (me) wishes to edit the code of a module and then re-load it into the program without halting execution.
can this be done?
i have tried running import a second time on an updated module.py, but the changes are not picked up
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
虽然
reload
确实会重新加载模块,正如另一个答案提到的那样,您需要采取相当多的预防措施才能使其顺利工作 - 对于某些您可能认为会很容易工作的事情,您将面临相当大的困难实际需要的工作量令人震惊。如果您曾经使用过
from module import afunction
形式,那么您几乎可以确定reload
不起作用:您必须独占导入模块,如果你希望重新加载
做一些有用的事情(否则你必须以某种方式追逐所有从模块各处导入的点点滴滴,并重新绑定它们中的每一个 - eep;-)。请注意,无论如何,我更喜欢遵循此规则,无论我是否计划进行任何重新加载,但是,对于重新加载,它是至关重要的。困难的问题是:如果您在任何地方都存在模块先前版本中存在的类实例,则重新加载本身绝对不会执行任何升级这些实例的操作。 这个问题确实是一个难题; Python Cookbook(第二版)中最长、最难的食谱之一是关于如何对模块进行编码以支持这种“实际升级现有实例的重新加载”。当然,这仅在您以 OOP 风格编程时才重要,但是...任何复杂到需要“重新加载此插件”功能的 Python 程序非常很可能其中包含大量 OOP,所以它是几乎不是一个小问题。
重新加载文档非常完整,确实提到了这个问题,但没有给出提示如何解决它。 此食谱,作者:Michael Hudson,来自在线 Python Cookbook 更好,但这只是我们演变为印刷版(第二版)的开始——菜谱 20.15,其在线版本是 此处(除非您注册 O'Reilly 商业在线图书服务的免费限时预览,否则不完整)。
While
reload
does reload a module, as the other answer mentions, you need quite a few precautions to make it work smoothly -- and for some things you might believe would work easily, you're in for quite a shock in terms of amount of work actually needed.If you ever use the form
from module import afunction
, then you've almost ensuredreload
won't work: you must exclusively import modules, never functions, classes, etc, from inside modules, if you want to have any hope ofreload
doing something useful all all (otherwise you'd have to somehow chases all the bits and pieces imported here and there from the module, and rebind each and every one of them -- eep;-). Note that I prefer following this rule anyway, whether I plan to do any reloading or not, but, with reload, it's crucial.The difficult problem is: if you have, alive anywhere, instances of classes that existed in the previous version of the module,
reload
per se will do absolutely nothing to upgrade those instances. That problem is a truly hard one; one of the longest, hardest recipes in the Python Cookbook (2nd edition) is all about how to code your modules to support such "reload that actually upgrades existing instances". This only matters if you program in OOP style, of course, but... any Python program complex enough to need "reload this plugin" functionality is very likely to have lots of OOP in it, so it's hardly a minor issue.The docs for reload are pretty complete and do mention this issue, but give no hint how to solve it. This recipe by Michael Hudson, from the Python Cookbook online, is better, but it's only the start of what we evolved into the printed (2nd edition) -- recipe 20.15, the online version of that is here (incomplete unless you sign up for a free time-limited preview of O'Reilly's commercial online books service).
reload() 将满足您的需要。您只需要注意重新编译时模块中执行的代码即可;如果您的模块仅包含定义,通常是最简单的。
reload() will do what you need. You just have to be careful about what code executes in your module upon re-compile; it is usually easiest if your module just contains definitions.
使用内置命令:
如何卸载(重新加载)Python 模块?
use the builtin command:
How do I unload (reload) a Python module?
您可能会从 livecoding 模块中得到一些帮助。
You may get some use from the livecoding module.
亚历克斯的回答和其他人的回答涵盖了一般情况。
但是,由于您正在处理的这些模块是您自己的,并且您只需编辑它们,因此可以实现某种本地重新加载机制,而不是依赖于内置重新加载。您可以将模块加载器构建为加载文件、编译文件并将它们评估到特定命名空间中并告诉调用代码它已准备就绪的东西。您可以通过确保有一个合适的
init
函数来正确地重新初始化模块来处理重新加载。我假设您只会编辑这些。这需要一些工作,但可能很有趣并且值得您花时间。
Alex's answer and the others cover the general case.
However, since these modules you're working on are your own and you'll edit only them, it's possible to implement some kind of a local reloading mechanism rather than rely on the builtin reload. You can architect your module loader as something that loads up the files, compiles it and evals them into a specific namespace and tells the calling code that it's ready. You can take care of reloading by making sure that there's a decent
init
function which reinitialises the module properly. I assume you'll be editing only these.It's a bit of work but might be interesting and worth your time.