用 pyximport 重新加载模块?

slu*_*shi 7 python cython

我有一个 python 程序,它在运行之前加载了相当多的数据。因此,我希望能够在不重新加载数据的情况下重新加载代码。使用普通的python,importlib.reload一直工作正常。下面是一个例子:

设置.py:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

extensions = [
    Extension("foo.bar", ["foo/bar.pyx"],
              language="c++",
              extra_compile_args=["-std=c++11"],
              extra_link_args=["-std=c++11"])
]
setup(
    name="system2",
    ext_modules=cythonize(extensions, compiler_directives={'language_level' : "3"}),
)
Run Code Online (Sandbox Code Playgroud)

foo/bar.py

cpdef say_hello():
    print('Hello!')
Run Code Online (Sandbox Code Playgroud)

跑步者.py:

import pyximport
pyximport.install(reload_support=True)

import foo.bar
import subprocess
from importlib import reload

if __name__ == '__main__':

    def reload_bar():
        p = subprocess.Popen('python setup.py build_ext --inplace',
                             shell=True,
                             cwd='<your directory>')
        p.wait()

        reload(foo.bar)
        foo.bar.say_hello()
Run Code Online (Sandbox Code Playgroud)

但这似乎不起作用。如果我编辑 bar.pyx 并运行,reload_bar我看不到我的更改。我也尝试过pyximport.build_module(),但没有运气 - 模块重建但没有重新加载。我在“普通”python shell 中运行,而不是在 IPython 中运行,如果它有所不同的话。

Dil*_*vis 6

我能够得到一个适用于 Python 2.xa 的解决方案比 Python 3.x 容易得多。无论出于何种原因,Cython 似乎正在缓存.so它从中导入模块的可共享对象 ( ) 文件,即使在运行时重建和删除旧文件后,它仍然从旧的可共享对象文件中导入。然而,这无论如何都不是必需的(当你import foo.bar,它不会创建一个),所以我们可以跳过这个。

最大的问题是即使在reloading之后,python 仍然保留对旧模块的引用。正常的 python 模块似乎可以找到,但与 cython 无关。为了解决这个问题,我运行执行两个语句来代替reload(foo.bar)

del sys.modules['foo.bar']
import foo.bar
Run Code Online (Sandbox Code Playgroud)

这成功地(尽管可能效率较低)重新加载了 cython 模块。运行该子进程的 Python 3.x 中唯一存在的问题会创建有问题的可共享对象。相反,一起跳过所有这些,让模块import foo.bar发挥其魔力pyximporter,然后为您重新编译。我还在pyxinstall命令中添加了一个选项来指定语言级别以匹配您在setup.py

pyximport.install(reload_support=True, language_level=3)
Run Code Online (Sandbox Code Playgroud)

所以大家一起:

跑步者.py

import sys
import pyximport
pyximport.install(reload_support=True, language_level=3)

import foo.bar

if __name__ == '__main__':
    def reload_bar():
        del sys.modules['foo.bar']
        import foo.bar

    foo.bar.say_hello()
    input("  press enter to proceed  ")
    reload_bar()
    foo.bar.say_hello()
Run Code Online (Sandbox Code Playgroud)

其他两个文件保持不变

跑步:

Hello!
  press enter to proceed
Run Code Online (Sandbox Code Playgroud)

-replace"Hello!"富/ bar.pyx"Hello world!",并按Enter

Hello world!
Run Code Online (Sandbox Code Playgroud)