【问题标题】:How does module reload in python3.7 work?python3.7中的模块重载是如何工作的?
【发布时间】:2019-07-03 09:53:48
【问题描述】:

模块重载如何在 python 3.7.1 中工作?

设置和总结

我在 Linux 中运行 python 3.7.1。我正在开发一个 C 模块,一旦模块发生更改,重新加载模块会非常方便。我关注了How do I unload (reload) a Python module?,但我无法让它在这种环境中工作。

为了演示我的问题,我根据教程中的 SPAM 示例编写了一个简单的模块,该模块返回模块的构建时间。它永远不会重新加载。

代码

实现是教程中的垃圾邮件示例。它有一个函数 hello,它返回构建时间:

return Py_BuildValue("s", __TIME__);

我正在使用以下 python 脚本编译和加载:

import os
import helloworld
print(helloworld.hello('test'))
os.system("touch helloworld.c")
os.system("python3 setup.py build")
os.system("python3 setup.py install --user")
from importlib import reload
helloworld=reload(helloworld)
print(helloworld.hello('test'))

模块导入,触摸主文件,编译安装,然后重新加载。

输出

模块应该在重新加载后显示新的编译时间,但输出没有改变(我省略了一些调试消息,输出是第一行/最后一行,08:04:20):

python driver.py
08:04:20
running build
running build_ext
building 'helloworld' extension
gcc ...
running install
running build
running build_ext
running install_lib
copying build/lib.linux-x86_64-3.7/helloworld.cpython-37m-x86_64-linux-gnu.so -> /home/wuebbel/.local/lib/python3.7/site-packages
running install_egg_info
Removing /home/wuebbel/.local/lib/python3.7/site-packages/HelloWorld-2.1-py3.7.egg-info
Writing /home/wuebbel/.local/lib/python3.7/site-packages/HelloWorld-2.1-py3.7.egg-info
08:04:20

再次运行脚本会加载正确的模块并显示新时间:

wuebbel@02e267406db3:~/Projekte/Mandelbrot Demos/helloworld$ python driver.py
08:16:58
...
08:16:58

似乎我的模块永远不会重新加载。这样做的正确方法是什么?

【问题讨论】:

  • 你可以试试sys.modules.pop("helloworld"),然后重新加载
  • 我想知道我提供的解决方法是否有效。根据我发布的其他链接,我对此表示怀疑

标签: python module reload


【解决方案1】:

我怀疑重新加载包含已编译代码的模块的可行性,阅读此答案:https://stackoverflow.com/a/48814213/6451573 这表明 PEP 489 更改了模块重新加载(在 python 3.6 和 3.7 之间),可能“破坏”共享库重新加载。

由于共享库加载的限制(POSIX 上的 dlopen 和 Windows 上的 LoadModuleEx),通常不可能在磁盘上更改后加载已修改的库。

这可以解释你遇到的问题。

如果这是一个操作案例,我建议你有一个创建包的主 python 程序,然后使用单独的 python 进程来加载它。

subprog.py:

import helloworld
print(helloworld.hello('test'))

master.py

import os,subprocess,sys
def runit():
   subprocess.run([sys.executable,os.path.join(os.path.dirname(__file__),"subprog.py")])

runit()

os.system("touch helloworld.c")
os.system("python3 setup.py build")
os.system("python3 setup.py install --user")

runit()

使用sys.executable 确保相同的python 可执行文件用于主python 进程和子进程,因此更加透明。

【讨论】:

  • 感谢您的快速回答。我同意 DLL 重新加载很难,但它通常应该可以工作 - 毕竟,它在官方 repo 中,似乎没有其他人抱怨 - 所以我仍然认为我做错了什么(并且它在 Matlab 中适用于 mex 文件,如果我没记错的话)。不幸的是,您的解决方法没有帮助,结果与以前相同。
  • 我已经编辑提出了一个带有子流程的解决方案。解决方法也是,稍微差一点,但应该可以工作
  • 感谢您的更新。请注意,subprocess.run 的 API 已更改,我必须按照 `print(subprocess.run([sys.executable,"subprocess.py"],capture_output=True)) ` 的方式做一些事情。虽然这可行,但这并不是我真正需要的——调用子进程时调用者进程的变量会丢失,我需要内部交互等等。我目前的结论是,我无法让它按照我想要的方式工作。我接受你的回答,因为这可能是最好的。
猜你喜欢
  • 1970-01-01
  • 2014-10-29
  • 2020-01-01
  • 1970-01-01
  • 2011-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
相关资源
最近更新 更多