当我使用Py_InitModule
注册回调时,如果稍后将结构中的函数指针更改为指向新函数,则会调用新函数。但是,如果我更改名称,则无法识别新名称。Py_InitModule复制名称而不是函数指针?
#include <Python.h>
PyObject* foo1(PyObject *self, PyObject *args)
{
printf("foo1\n");
Py_RETURN_NONE;
}
PyObject* foo2(PyObject *self, PyObject *args)
{
printf("foo2\n");
Py_RETURN_NONE;
}
int main()
{
PyMethodDef methods[] = {
{ "foo", foo1, METH_VARARGS, "foo" },
{ 0, 0, 0, 0 }
};
Py_Initialize();
Py_InitModule("foo", methods);
PyRun_SimpleString("import foo\n");
PyRun_SimpleString("foo.foo()\n");
methods[0].ml_meth = foo2;
PyRun_SimpleString("foo.foo()\n");
methods[0].ml_name = "foo2";
PyRun_SimpleString("foo.foo()\n");
PyRun_SimpleString("foo.foo2()\n");
return 0;
}
这给出了以下的输出:
foo1 foo2 foo2 Traceback (most recent call last): File "", line 1, in AttributeError: 'module' object has no attribute 'foo2'
这似乎是一个非常不一致的行为。我第一次遇到它时,我使用了一个栈变量PyMethodDef methods
,一旦变量超出了范围,程序崩溃了,我仍然试图从python调用C++回调函数。所以我测试了改变指针确实改变了哪个函数被调用,即使我没有用另一个Py_InitModule
调用重新注册它。但同时,更改名称不会有这种行为。
到目前为止,我相当确定只要python代码试图调用方法(即不能是堆栈/局部变量),但是只有函数指针本身被使用,我才能确定PyMethodDef
需要活着。
这是故意的行为还是一些疏忽?该文档没有提到任何关于PyMethodDef生命周期的信息,我可以找到。
这是预期的。你觉得,PyInit_Module没有初始化什么?它告诉解释器定义哪些属性/方法以避免稍后检查。如果你想动态地重命名一个函数,你必须1)从解释器中获取模块对象2)使用'PyObject_SetAttr'(或类似的,我不记得确切的名字)来设置模块对象的属性。 – Bakuriu
@Bakuriu谢谢,但为什么'ml_math'字段没有被复制呢?也就是说,为什么稍后改变它将被调用的函数热插拔? – sashoalm