本文介绍了使用非内置类型从C ++调用Cython的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Python和Cython扩展用C ++编写的库的功能。我在C ++中有MyClass类,这对于我的lib是必不可少的。而且我在Python中使用了很多包装类PyMyClass。所以我想使用C ++中的函数(以PyMyClass作为参数)。我怎么能做到这一点?

i'm trying to extend functionality of my lib written in C++ with Python and Cython. I have class MyClass in C++ wich is essential for my lib. And i'm using a lot it's wrapper class PyMyClass in Python. So i want to use functions (with PyMyClass as argument) from C++. How i can accomplish this?

我想象是这样的:

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

myclass.h

myclass.h

namespace classes {
    class MyClass
    {

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

myclass.cpp

myclass.cpp

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

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

pymyclass.pyx

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

cdef class 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字段?我的意思是这样的:

I understand that i can add get_x(), get_y() and set_x(int), set_y(int) to MyClass and just copy all the fields from MyClass to PyMyClass. But PyMyClass has already a pointer to MyClass. Is it possible just assign address of MyClass instance to PyMyClass field? I mean something like this:

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(class)
other_py_func(pyclass)

Then Cython function will look like cdef public my_func(MyClass *class): pyclass = PyMyClass(class) other_py_func(pyclass)

推荐答案

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

To create a Cython extension class from existing C++ pointer, use a factory function.

例如:

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 对象的地方使用。

That gives you access to the C++ class via its pointer without copying or moving any data. PyMyClass_factory can be used anywhere you want to return a Python PyMyClass object from an existing C++ pointer.

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

Note that Python does not support function overloading (nor Cython) so you cannot have two __cinit__ signatures, one with no arguments and one that creates a new C++ class from two integers.

如果要通过Cython创建新的C ++类,则需要一个新的工厂函数来执行此操作,如上例所示。

If you want to create a new C++ class via Cython, a new factory function to do that is needed as per above example.

它看起来像:

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

Also, the cdef public my_func(MyClass var) is not needed. public is for making Cython functions available to C/C++, it does not mean the same thing it does in C++. If you do not intend to use my_func outside Python/Cython, public is not needed.

如果您打算通过Python使用该函数,则必须为 def cpdef ,而不是 cdef

If you intend to use that function via Python then it must be def or cpdef, not cdef.

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

Finally, you probably want to define the external definition as nogil and use with nogil when calling C++ functions, for obvious reasons. For example,

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

这篇关于使用非内置类型从C ++调用Cython的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-21 23:00