从c ++调用Cython而不是内置类型

时间:2017-11-02 11:21:52

标签: c++ cython

我试图用Python和Cython扩展用C ++编写的lib的功能。我在C ++中有MyClass类,这对我的lib来说至关重要。我在Python中使用了很多它的包装类PyMyClass。所以我想使用C ++中的函数(使用PyMyClass作为参数)。我怎么能做到这一点?

我想象它是这样的:

cdef public my_func(MyClass class):
     *cast MyClass to PyMyClass*
     other_py_func(PyMyClass)

myclass.h

namespace classes {
    class MyClass
    {

    public:
        explicit MyClass(int x, int y);
        int sum();
    private:
        int a;
        int b;
    };
}

myclass.cpp

MyClass::MyClass(int x, int y)
{
    a = x;
    b = y;
}

MyClass::sum()
{
    return a + b
}

pymyclass.pyx

cdef extern from "myclass.h" namespace "classes":
    cdef cppclass MyClass:
        MyClass(int x, int y) except +
        int sum()

    cdef public my_func(MyClass var):
         print "It is python"

cdef类PyMyClass(object):         cdef MyClass * c_class

    def __cinit__(self, int x, int y):
        self.c_class = new MyClass(x,y)

   def __dealoc__(self):
       del self.c_class.sum()

    def sum(self):
        return self.c_class.sum()

据我所知,我可以将get_x(),get_y()和set_x(int),set_y(int)添加到MyClass,只需将MyClass中的所有字段复制到PyMyClass即可。但PyMyClass已经有一个指向MyClass的指针。是否可以将MyClass实例的地址分配给PyMyClass字段?我的意思是这样的:

cdef class PyMyClass(object):
       cdef MyClass *c_class

       def __cinit__(self, int x, int y):
            self.c_class = MyClass(x,y)

       def __cinit__(self, void * ptr):
           self.c_class = (Antenna *)ptr

       def __dealoc__(self):
           del self.c_class.sum()

       def sum(self):
            return self.c_class.sum()

然后Cython函数看起来像     cdef public my_func(MyClass * class):          pyclass = PyMyClass(类)          other_py_func(pyclass)

1 个答案:

答案 0 :(得分:2)

要从现有C ++指针创建Cython扩展类,请使用工厂函数。

例如:

cdef class PyMyClass:
   cdef MyClass *c_class

   def __cinit__(self):
        # Set pointer to null on object init
        self.c_class = NULL

   def __dealoc__(self):
       if self.c_class is not NULL:
           del self.c_class

   def sum(self):
        return self.c_class.sum()

cdef object PyMyClass_factory(MyClass *ptr):
    cdef PyMyClass py_obj = PyMyClass()
    # Set extension pointer to existing C++ class ptr
    py_obj.c_class = ptr
    return py_obj

这使您可以通过其指针访问C ++类,而无需复制或移动任何数据。 PyMyClass_factory可以在任何想要从现有C ++指针返回Python PyMyClass对象的地方使用。

请注意,Python不支持函数重载(也不支持Cython),因此您不能拥有两个__cinit__个签名,一个没有参数,另一个从两个整数创建一个新的C ++类。

如果你想通过Cython创建一个新的C ++类,那么就需要一个新的工厂函数来实现它。

看起来像是:

cdef object PyMyClass_factory_new(int x, int y):
    cdef MyClass cpp_obj = new MyClass(x, y)
    cdef PyMyClass py_obj = PyMyClass()
    py_obj.c_class = &cpp_obj
    return py_obj

此外,不需要cdef public my_func(MyClass var)public用于使Cython函数可用于C / C ++,它并不意味着它在C ++中的作用。如果您不打算在Python / Cython之外使用my_func,则不需要public

如果您打算通过Python使用该功能,那么它必须是defcpdef,而不是cdef

最后,您可能希望将外部定义定义为nogil,并在调用C ++函数时使用with nogil,原因很明显。例如,

cdef extern from "myclass.h" namespace "classes" nogil:
    <..>

cdef class PyMyClass:
    <..>

    def sum(self):
        cdef int ret
        with nogil:
            ret = self.c_class.sum()
        return ret