How to Reload a Python3 C extension module?

一个人想着一个人 提交于 2019-12-01 06:20:31

You can reload modules in Python 3.x by using the imp.reload() function. (This function used to be a built-in in Python 2.x. Be sure to read the documentation -- there are a few caveats!)

Python's import mechanism will never dlclose() a shared library. Once loaded, the library will stay until the process terminates.

Your options (sorted by decreasing usefulness):

  1. Move the module import to a subprocess, and call the subprocess again after recompiling, i.e. you have a Python script do_stuff.py that simply does

    import mycext
    mycext.do_stuff()
    

    and you call this script using

    subprocess.call([sys.executable, "do_stuff.py"])
    
  2. Turn the compile-time constants in your header into variables that can be changed from Python, eliminating the need to reload the module.

  3. Manually dlclose() the library after deleting all references to the module (a bit fragile since you don't hold all the references yourself).

  4. Roll your own import mechanism.

    Here is an example how this can be done. I wrote a minimal Python C extension mini.so, only exporting an integer called version.

    >>> import ctypes
    >>> libdl = ctypes.CDLL("libdl.so")
    >>> libdl.dlclose.argtypes = [ctypes.c_void_p]
    >>> so = ctypes.PyDLL("./mini.so")
    >>> so.PyInit_mini.argtypes = []
    >>> so.PyInit_mini.restype = ctypes.py_object 
    >>> mini = so.PyInit_mini()
    >>> mini.version
    1
    >>> del mini
    >>> libdl.dlclose(so._handle)
    0
    >>> del so
    

    At this point, I incremented the version number in mini.c and recompiled.

    >>> so = ctypes.PyDLL("./mini.so")
    >>> so.PyInit_mini.argtypes = []
    >>> so.PyInit_mini.restype = ctypes.py_object 
    >>> mini = so.PyInit_mini()
    >>> mini.version
    2
    

    You can see that the new version of the module is used.

    For reference and experimenting, here's mini.c:

    #include <Python.h>
    
    static struct PyModuleDef minimodule = {
       PyModuleDef_HEAD_INIT, "mini", NULL, -1, NULL
    };
    
    PyMODINIT_FUNC
    PyInit_mini()
    {
        PyObject *m = PyModule_Create(&minimodule);
        PyModule_AddObject(m, "version", PyLong_FromLong(1));
        return m;
    }
    

there is another way, set a new module name, import it, and change reference to it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!