Python与动态扩展C++类

1 投票
1 回答
670 浏览
提问于 2025-04-17 04:16

我在使用Python时遇到了一个问题,涉及到我自定义的类型、函数和属性。

当我在Python中想给我的自定义类型(比如Vector4)设置一个属性时,我的代码在const char* attribute_name这个参数上得到了NULL(是的,我已经导入了我的模块)。

奇怪的是,当我在设置函数中硬编码属性名称时,我收到了一个错误:

SystemError: error return without exception set

我确实看到对象在Python中被创建(在C++中也是),所以我不认为这是问题所在。如果setattro钩子成功设置了属性,我会返回1,而且我看到代码在C++端被调用并设置了属性。在设置属性时没有出现错误或异常。

另外,当我在Python中调用我类的实例上的一个函数时,它调用的是在tp_getattro中设置的函数,而不是检查字典。

我不太确定为什么会这样,可能是因为我在设置一个字典并把我的函数放在里面,而不是通过PyModuleDef数组来做,因此在调用PyType_Ready时函数没有被看到。

有没有人知道这可能是什么原因?我们使用的是Python 3.2。


相关信息:

我有一个基础类型(tp_newtp_dealloc),然后我在运行时创建派生类型。派生类型有一个字典,tp_basetp_getattrotp_setattro

这是函数如何绑定到Python类/类型的:

PyMethodDef newMethod;
newMethod.ml_doc = newMethod.ml_name = funcName;
newMethod.ml_flags = METH_VARARGS;
newMethod.ml_meth = pythonFunc;

PyGeneralObj* selfFake = PyObject_New(PyGeneralObj, &MetaEngineType);
selfFake->className = className;
selfFake->funcName = funcName;
Py_INCREF((PyObject*)selfFake);

PyObject *func = PyCFunction_New(&newMethod, (PyObject*)selfFake);
PyObject *method = PyInstanceMethod_New(func);

ErrorIf((method == NULL), "Python: Cannot create instance function. %s", 
funcName);

ErrorIf((PyDict_SetItem(classObj->m_pyClassType->tp_dict,            
PyReturnStr(newMethod.ml_name), method) == -1), 
"Python: Cannot create function in dictionary.");

Py_DECREF(func);
Py_DECREF(method);

其中funcName和className是const char*。pythonFunc是一个通用的Python函数,用于处理调用我们所有绑定到元系统的函数。classObj是指向一个PythonClass的指针,它有一个成员m_pyClassType(类型为PyTypeObject)。

PyGeneralObj是一个新对象,有两个const char*和一个void*(这是C++中的对象)。

我执行PyType_Ready时没有错误,然后增加我的类型。接着我把这个对象添加到通过PyImport_ImportModule获得的模块PyObject中。我把我的主模块附加到运行时,并初始化Python并导入我的模块。


如果需要更多信息或代码,我可以再发一些。我希望这些内容能让人明白,这是我第一次在StackOverflow上发帖。

为了澄清,我们希望有动态属性,这些属性完全在C++端解析。对于函数,我希望能够覆盖PyObject* self参数,以便我可以获取需要调用的函数的字符串名称。

我们不想使用像Boost、Cython等第三方库或接口。

1 个回答

0

问题出在我对getattro这个函数的实现上。

撰写回答