从 Cython 模块导出包装的 C++ 类
Exporting wrapped C++ classes from Cython modules
假设我正在尝试包装 vector
。
module/__init__.pxd:
from libcpp.vector cimport vector
from libc.stdint cimport uint32_t
cdef class MyVector:
cdef vector[uint32_t]* thisptr
module/__init__.pyx:
from libc.stdint cimport uint32_t
from libcpp.vector cimport vector
from cython.operator cimport dereference as deref
cdef class MyVector:
# the field declaration is in *.pxd
def __cinit__(self):
self.thisptr = new vector[uint32_t]()
self.thisptr.push_back(42)
def __dealloc__(self):
del self.thisptr
self.thisptr = <vector[uint32_t]*> NULL
def mysize(self):
return self.thisptr.size()
def myget(self):
return deref(self.thisptr)[0]
module/__init__.pyxbld
和 run.pyxbld:
def make_ext(modname, pyxfilename):
from distutils.extension import Extension
return Extension(
name=modname,
sources=[pyxfilename],
language='c++'
)
run.pyx:
from module cimport MyVector
cdef main():
obj = MyVector()
print(obj.thisptr.size()) # 1
print(obj.mysize()) # 1
print(obj.myget()) # 42
main()
test.py:
import pyximport
pyximport.install()
import run
当我 运行 test.py
时,它崩溃并出现以下回溯:
Traceback (most recent call last):
File "/usr/lib64/python3.4/site-packages/pyximport/pyximport.py", line 210, in load_module
mod = imp.load_dynamic(name, so_path)
File "module/__init__.pxd", line 5, in init run (/home/pastafarianist/.pyxbld/temp.linux-x86_64-3.4/pyrex/run.cpp:918)
cdef class MyVector:
AttributeError: 'module' object has no attribute 'MyVector'
如果我将 module/__init__.pyx
移动到 module.pyx
并将 module/__init__.pxd
移动到 module.pxd
,则相同的代码会起作用。我缺少什么以及如何解决它?
其他一些相关问题。
- 有没有什么方法可以将模板化包装器暴露给 Cython 代码,这样我就可以
MyVector[uint16_t]
而无需编写另一个包装器?
- 我为每个与 C++ 代码交互的源文件添加
pyxbld
文件是否正确?这是多余的吗? (我喜欢 pyximport
的便利,而且我不想每次都手动重新编译代码,而我仍在努力让它工作。)
- 如何将
module
编译为独立扩展? setup.py
应该是什么样子?
- 在上面的代码中,我在调用 C++ 方法之前从未使用过
deref
。 Cython 如何理解我的意思 ->
和我的意思 .
?
对于这些问题中的任何一个,我将不胜感激。
UPD: 实际上,我在包装 Google 的 sparsehash
,我想出了一个 way to do what I wanted,但它看起来像黑魔法。我仍然希望澄清此错误的原因以及如何正确编写 Cython 包装器。
您应该考虑使用 'swig'。该工具将创建您在 C++ 和 Python 之间进行交互所需的所有代码。
Link to swig website.
我在一个复杂的项目中使用了 swig,效果非常好。
无论如何,如果您不想在代码中使用此框架,可以使用 swig 创建的代码作为参考。
您的主要问题是 。因此,您可以通过制作一个空的 __init__.py
文件来解决问题。这一切感觉就像一个混乱的边缘案例。在您的原始代码中,MyVector
class 永远不会添加到模块中,因此它无法找到您描述的错误。
您的其他问题的简短回答是:
否 - 不幸的是,没有构建模板化包装器的好方法 class。不过,您不需要为仅在 Cython 中使用的任何内容构建包装器 classes。
和
我认为这些最终会成为非常重要的答案,因此我将跳过它们。一般来说,setup.py
似乎比 pyximport
更受欢迎,文档中有关于如何使用它的很好的例子。
Cython 在内部跟踪对象的类型。只要它知道它正在使用指针,它就会替换 ->
,否则替换 .
是相当简单的,所以正如你所说,你不必自己这样做。
假设我正在尝试包装 vector
。
module/__init__.pxd:
from libcpp.vector cimport vector
from libc.stdint cimport uint32_t
cdef class MyVector:
cdef vector[uint32_t]* thisptr
module/__init__.pyx:
from libc.stdint cimport uint32_t
from libcpp.vector cimport vector
from cython.operator cimport dereference as deref
cdef class MyVector:
# the field declaration is in *.pxd
def __cinit__(self):
self.thisptr = new vector[uint32_t]()
self.thisptr.push_back(42)
def __dealloc__(self):
del self.thisptr
self.thisptr = <vector[uint32_t]*> NULL
def mysize(self):
return self.thisptr.size()
def myget(self):
return deref(self.thisptr)[0]
module/__init__.pyxbld
和 run.pyxbld:
def make_ext(modname, pyxfilename):
from distutils.extension import Extension
return Extension(
name=modname,
sources=[pyxfilename],
language='c++'
)
run.pyx:
from module cimport MyVector
cdef main():
obj = MyVector()
print(obj.thisptr.size()) # 1
print(obj.mysize()) # 1
print(obj.myget()) # 42
main()
test.py:
import pyximport
pyximport.install()
import run
当我 运行 test.py
时,它崩溃并出现以下回溯:
Traceback (most recent call last):
File "/usr/lib64/python3.4/site-packages/pyximport/pyximport.py", line 210, in load_module
mod = imp.load_dynamic(name, so_path)
File "module/__init__.pxd", line 5, in init run (/home/pastafarianist/.pyxbld/temp.linux-x86_64-3.4/pyrex/run.cpp:918)
cdef class MyVector:
AttributeError: 'module' object has no attribute 'MyVector'
如果我将 module/__init__.pyx
移动到 module.pyx
并将 module/__init__.pxd
移动到 module.pxd
,则相同的代码会起作用。我缺少什么以及如何解决它?
其他一些相关问题。
- 有没有什么方法可以将模板化包装器暴露给 Cython 代码,这样我就可以
MyVector[uint16_t]
而无需编写另一个包装器? - 我为每个与 C++ 代码交互的源文件添加
pyxbld
文件是否正确?这是多余的吗? (我喜欢pyximport
的便利,而且我不想每次都手动重新编译代码,而我仍在努力让它工作。) - 如何将
module
编译为独立扩展?setup.py
应该是什么样子? - 在上面的代码中,我在调用 C++ 方法之前从未使用过
deref
。 Cython 如何理解我的意思->
和我的意思.
?
对于这些问题中的任何一个,我将不胜感激。
UPD: 实际上,我在包装 Google 的 sparsehash
,我想出了一个 way to do what I wanted,但它看起来像黑魔法。我仍然希望澄清此错误的原因以及如何正确编写 Cython 包装器。
您应该考虑使用 'swig'。该工具将创建您在 C++ 和 Python 之间进行交互所需的所有代码。 Link to swig website.
我在一个复杂的项目中使用了 swig,效果非常好。
无论如何,如果您不想在代码中使用此框架,可以使用 swig 创建的代码作为参考。
您的主要问题是 __init__.py
文件来解决问题。这一切感觉就像一个混乱的边缘案例。在您的原始代码中,MyVector
class 永远不会添加到模块中,因此它无法找到您描述的错误。
您的其他问题的简短回答是:
否 - 不幸的是,没有构建模板化包装器的好方法 class。不过,您不需要为仅在 Cython 中使用的任何内容构建包装器 classes。
和
我认为这些最终会成为非常重要的答案,因此我将跳过它们。一般来说,
setup.py
似乎比pyximport
更受欢迎,文档中有关于如何使用它的很好的例子。Cython 在内部跟踪对象的类型。只要它知道它正在使用指针,它就会替换
->
,否则替换.
是相当简单的,所以正如你所说,你不必自己这样做。