Python 和动态扩展 C++课程
所以我在 Python 中遇到了自定义类型、函数和属性的问题。
当我使用 Python 时,我想在我的自定义类型之一(例如 Vector4)上设置一个属性,我的代码的 const char* attribute_name
参数得到 NULL(是的,我正在导入我的模块)。
奇怪的是,当我在 setter 函数中对属性名称进行硬编码时,出现错误:
SystemError: error return without exception set
我确实看到在 Python 中创建了对象(并且再次在 C++ 中),所以我认为这不是问题。如果 setattro 钩子在 C++ 中成功设置了属性,我会返回 1,并且我看到代码被调用并在 C++ 端设置属性。设置属性时不会引发任何错误/异常。
此外,当我在 Python 中调用类实例上的函数时,它会调用 tp_getattro 中设置的函数,而不是检查字典。
我不完全确定为什么,也许是因为我设置了一个字典并将函数放入其中,而不是通过 PyModuleDef
数组执行此操作,因此当 时看不到函数>PyType_Ready
被调用。
有谁知道为什么会发生这种情况?我们使用的是 Python 3.2。
相关:
我有一个基本类型(tp_new
和 tp_dealloc
),然后在运行时创建派生类型。派生类型具有字典、tp_base
、tp_getattro
和 tp_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 的指针,该 PythonClass 具有成员 m_pyClassType(PyTypeObject 的类型)。
PyGeneralObj
是一个新对象,有两个 const char* 和一个 void* (这是 C++ 中的对象),
我执行 PyType_Ready
并没有收到错误,然后增加我的类型。然后,我将该对象添加到从 PyImport_ImportModule
给出的模块 PyObject 中。我确实将我的主模块附加到运行时并初始化 python 并导入我的模块。
如果需要更多信息/代码,我可以发布更多信息/代码。我希望这是有道理的,这是我第一次在 stackoverflow 上发帖。
为了澄清起见,我们希望拥有在 C++ 端完全解析的动态属性。对于函数,我希望能够重写 PyObject* self
参数,以便可以获得需要调用的函数的字符串名称。
我们不想使用第三方库/接口,例如 Boost、Cython 等。
So I'm running into a problem with my custom types, functions and attributes in Python.
When I'm in Python, and I want to set an attribute on one of my custom types (for example Vector4), my code gets a NULL for the const char* attribute_name
argument (and yes, I am importing my module).
Oddly enough, when I hard code the attribute name in my setter function, I get the error:
SystemError: error return without exception set
I do see the object getting created in Python (and again in C++), so I don't think that's the problem. I do return 1 if the setattro hook did successfully set the attribute in C++, and I see the code getting called and setting the attribute on the C++ side. There are no errors/exceptions that are raised when the attribute is being set.
Additionally, when I call a function on the instance of my class in Python, it calls the function set in tp_getattro
instead of checking the dictionary.
I'm not entirely sure why, maybe it's because I'm setting a dictionary and putting my functions in there, instead of doing it via a PyModuleDef
array, thus functions aren't being seen when PyType_Ready
is called.
Does anyone have any idea why this might be happening? We're using Python 3.2.
Relevant:
I have a base type (tp_new
and tp_dealloc
) and then I am creating derived types at runtime. The derived types have a dictionary, tp_base
, tp_getattro
and a tp_setattro
.
This is how functions are bound to Python class/types:
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);
Where funcName and className are const char*. pythonFunc is a generic python function that handles calling all of our functions that are bound to our meta system. classObj is a pointer to a PythonClass which has a member m_pyClassType (a typeof PyTypeObject).
PyGeneralObj
is a new object has two const char* and a void* (this is the object in C++)
I do PyType_Ready
and get no errors, and then increment my type. I then add the object to the module PyObject that I'm given from PyImport_ImportModule
. I do append my main module to the runtime and initalize python and import my module.
If more information/code is needed, I can post some more. I hope this makes sense, this is my first time posting on stackoverflow.
For clarification, we want to have dynamic attributes that are completely resolved on the C++ side. And for functions, I want to be able to override the PyObject* self
argument so that I can get the string name of the function that needs to be called.
We don't want to use third party libraries/interfaces like Boost, Cython and whatever.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题出在我的 getattro 实现上。
The problem was in my implementation of getattro.