0

我正在为 Python 制作 C++ 扩展,并且我正在尝试执行以下操作:

// this function assigns a C++ pointer to as attribute of a python object
void function1(PyObject* p){
    // equivalent of p.attr = cpp_attr;
    MyClass* cpp_attr = new MyClass();
    PyObject* args = PyTuple_Pack(cpp_attr);
    PyObject_SetAttrString(p, (char*)"attr", args);
}

我想检索此指针并将其设置为另一个 C++ 对象的属性。我知道如何获得,PyObject*但在那之后我不知道该怎么办了

MySecondClass::MySecondClass(PyObject* p){
    // get the attribute from p; equivalent of cpp_attr = p.attr
    PyObject* cpp_attr = PyObject_getAttrString(p, (char*)"attr"));
    // somehow get back the pointer to MyClass object created in function1
    
}

我查看了文档,但找不到任何返回原始类型的内容。有没有办法做到这一点?

谢谢

4

2 回答 2

1

很难绝对确定,但我怀疑MyClassPython 对象。这意味着您尝试将其存储为 Python 对象(例如使用PyTuple_Pack是完全错误的,并且会导致 Python 以意想不到的方式发生故障

将会发生的事情是 Python 将尝试将指针解释为 Python 对象,将尝试在该对象上使用其正常的引用计数机制(将以不可预知的方式更改它),并最终尝试释放该对象(使用 Python 机制,不删除...)如果对象的某些部分恰好等于 0。

有许多选项,基本上都围绕着创建一个包装器对象——一个用 C++ 定义的 Python 对象,它包含 C++ 对象的指针或值。

  1. 使用 Python C API 手动执行 -此答案提供了一个非常详尽的示例

  2. 查找PyCapsule 接口以在您的对象周围创建一个快速包装器。您将使用以下内容创建胶囊:

     PyObject* cap = PyCapsule_New(cpp_attr, "MyClass",
           [](PyObject* c) {
               auto deleteme = reinterpret_cast<MyClass*>(PyCapsule_GetPointer(c, "MyClass));
               delete deleteme;
           });
    

    然后你从胶囊中检索你的 C++ 类:

     reinterpret_cast<MyClass*>(PyCapsule_GetPointer(c, "MyClass))
    
  3. 使用 PyBind11、Cython、SWIG 等工具为您创建包装器对象。


另请注意,PyObject_SetAttrString不需要第三个参数是元组(除非您特别想存储元组......)。PyObject_Call您可能会将其与args 作为元组传递的地方混淆。

于 2020-06-27T07:58:24.497 回答
-1

假设您的调用PyTuple_Pack是正确的,那么您已经创建了一个PyTupleObject具有结构的:

typedef struct {
  PyObject_VAR_HEAD
  PyObject *ob_item[1];
} PyTupleObject;

PyTupleObject继承自PyObject struct具有以下成员的泛型:

struct _object *_ob_next;
struct _object *_ob_prev;
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;

Py_REFCNT您可以使用宏访问后两者Py_TYPE

ob_item[1]成员应该是指向最初分配的内存的指针。根据文档中宏的编写方式,您应该能够通过以下方式访问它

((PyTupleObject *)cpp_attr)->ob_item

如果您知道 C++ 指针的数据类型,那么您应该能够将其转换回。也许你可以试试

MyClass* cpp_att_again = reinterpret_cast<MyClass*>((PyTupleObject *)cpp_attr)->ob_item

希望这会为您指明正确的方向。您也许可以从类似的问题中获得更多见解。

于 2020-06-26T19:04:04.400 回答