如何在cython模块中使用外部包装类?

时间:2017-04-05 09:29:51

标签: python c++ cython

我有一个已经包装的外部类(我的意思是,它可以通过python直接访问而不需要进一步的努力),现在我希望它是一个更大的cython模块的 part (在换句话说,嵌入它)。

我可以明确地python-import它。但问题是外部类已经在cython模块中的extern函数中使用(因此该类最终在源代码中#include)。 Python导入需要编译模块,那么这两个模块可能有两个不同的同一类副本......

我应该如何在cython中使用外部已包装的类?

(可能过于简化)示例:

Foo.cpp中:

#include "Python.h"
#include "foo.hpp"

struct Foo_wrapper {
    PyObject_HEAD
    foo bar;
};

static int Foo_init(Foo_wrapper* self, PyObject* args, PyObject*) {
    ....
}

static PyTypeObject FooType {...};

Spam.pyx:

cdef extern from "some_functions.hpp":
    cdef some_function1(some_type); // this returns a wrapped foo object

def spam(arg1, arg2, arg3):
    // wrap arg1, arg2, arg3 to some_type
    return some_function1(an_instance_of_some_type); // huh? but foo isn't available here!

我想在spam.pyx中使用foo类。

1 个答案:

答案 0 :(得分:2)

这应该没问题(差不多)。这条cdef extern行不太正确:

cdef extern from "some_functions.hpp":
    object some_function1(some_type); // this returns a wrapped foo object

注意对object的更改 - 这告诉Cython该函数返回一个Python对象。 C / C ++声明如下:

PyObject* some_function1(some_type);
// or
Foo_wrapper* some_function1(some_type);

要么工作。

Cython代码可以正常使用的原因是PyObject_HEAD包含指向ob_type的指针PyTypeObject FooType。这是在创建对象时设置的。 PyTypeObject包含Python解释器使用返回对象所需的所有细节,因此一切都应该正常工作。

整个事情基本上等同于Python代码:

# in "somemodule.py"
def a_function():
    import something_else
    return something_else.Class()

Python解释器可以使用返回的值,尽管“global”命名空间中不知道Class

要注意的一件事是,在创建Foo之前,应确保至少调用Foo_wrapper模块初始化函数一次。原因是此函数通常会执行一些操作,例如调用PyType_Ready(&FooType)以确保FooType已正确设置。一种简单的方法是将以下行添加到some_function1

PyObject* m = PyImport_ImportModule("Foo");
if (m==NULL) return NULL; // an error
Py_CLEAR(m); // don't need to keep a reference to it

但是还有其他方法可以做同样的事情。