Python 和动态扩展 C++课程

发布于 2024-12-09 11:34:27 字数 2248 浏览 3 评论 0原文

所以我在 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_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 的指针,该 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柠檬色的秋千 2024-12-16 11:34:27

问题出在我的 getattro 实现上。

The problem was in my implementation of getattro.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文