问题描述
我正在尝试使用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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!