在Cython中,此方法的工作方式是通过使用工厂类从共享指针中创建Python对象。这使您无需复制即可访问基础C / C ++结构。
Cython代码示例:
<..>cdef class MyStruct: cdef shared_ptr[mystruct] ptr def __cinit__(self): # Do not create new ref here, we will # pass one in from Cython pre self.ptr = NULL def __dealloc__(self): # Do de-allocation here, important! if self.ptr is not NULL: <de-alloc> <rest per MyStruct pre above>cdef object PyStruct(shared_ptr[mystruct] MyStruct_ptr): """Python object factory class taking Cpp mystruct pointer as argument """ # Create new MyStruct object. This does not create # new structure but does allocate a null pointer cdef MyStruct _mystruct = MyStruct() # Set pointer of cdef class to existing struct ptr _mystruct.ptr = MyStruct_ptr # Return the wrapped MyStruct object with MyStruct_ptr return _mystructdef make_structure(): """Function to create new Cpp mystruct and return python object representation of it """ cdef MyStruct mypystruct = PyStruct(new mystruct) return mypystruct
注意,参数的类型
PyStruct是 指向 Cpp结构的 指针 。
mypystruct然后是
MyStructfactory类返回的class的python对象,它引用的是Cpp
mystruct而不进行复制。
mypystruct可以
def根据
make_structure代码在cython函数中安全返回,并在python空间中使用。
要返回现有Cpp
mystruct指针的Python对象,只需将其包装为
PyStructlike
return PyStruct(my_cpp_struct_ptr)
您的Cython代码中的任何位置。
显然只有
def函数可见,因此如果要在Python空间中使用Cpp函数调用,也需要在MyStruct中包装它们,至少,如果要让Cython类内部的Cpp函数调用放开GiL(可能出于明显的原因值得这么做)。
有关真实示例,请参见此Cython扩展代码和Cython中的基础C代码绑定。另请参见此代码,了解有关放开GIL的C函数调用的Python函数包装的信息。不是Cpp,但同样适用。
另请参见有关何时需要工厂类/功能的官方Cython文档(
Note that all constructor arguments will be passed as Pythonobjects)。对于内置类型,Cython会为您执行此转换,但是对于自定义结构或对象,需要工厂类/函数。
CPP的结构初始化可以在处理
__new__中
PyStruct,如果需要上面,如果你想在工厂类实际上是创建C
++结构为你(取决于所使用的情况下,真的),每建议。
具有指针参数的工厂类的好处是,它允许您使用C / C
++结构的现有指针并将其包装在Python扩展类中,而不必始终创建新的指针。例如,拥有多个引用同一基础C结构的Python对象将是绝对安全的。Python的引用计数确保它们不会过早地解除分配。尽管在分配时仍应检查null,因为共享指针可能已经被显式分配(例如,by
del)。
请注意,即使创建新的python对象指向相同的C ++结构,也存在一些开销。不是很多,但仍然。
IMO对C / C 指针的这种自动取消分配和引用计数是Python C扩展API的最大功能之一。由于所有这些作用于Python对象(单独),因此C /
C 结构需要包装在兼容的Python
object类定义中。
注意-我的经验主要是在C中,上面的内容可能需要调整,因为我比C ++的共享指针更熟悉常规C指针。



