python - 从 Cython 模块导出包装的 C++ 类

标签 python c++ wrapper cython

假设我正在尝试包装 vector

模块/__init__.pxd:

from libcpp.vector cimport vector
from libc.stdint cimport uint32_t

cdef class MyVector:
    cdef vector[uint32_t]* thisptr

模块/__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__.pyxbldrun.pyxbld:

def make_ext(modname, pyxfilename):
    from distutils.extension import Extension
    return Extension(
        name=modname,
        sources=[pyxfilename],
        language='c++'
    )

运行.pyx:

from module cimport MyVector

cdef main():
    obj = MyVector()
    print(obj.thisptr.size()) # 1
    print(obj.mysize()) # 1
    print(obj.myget())  # 42

main()

测试.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 移动到 ,则相同的代码有效模块.pxd。我缺少什么以及如何解决?

其他一些相关问题。

  1. 有什么方法可以将模板化包装器暴露给 Cython 代码,这样我就可以拥有 MyVector[uint16_t] 而无需编写另一个包装器?
  2. 我为每个与 C++ 代码交互的源文件添加 pyxbld 文件是否正确?这是多余的吗? (我喜欢 pyximport 的便利,我不想每次都手动重新编译代码,而我仍在努力让它工作。)
  3. 如何将 module 编译成独立的扩展? setup.py 应该是什么样子?
  4. 在上面的代码中,我在调用 C++ 方法之前从未使用过 deref。 Cython 如何理解我指的是 ->.

如果您能帮助我解决这些问题,我将不胜感激。


UPD:实际上,我正在包装 Google 的 sparsehash,并且我找到了一个 way to do what I wanted , 但它看起来像黑魔法。我仍然希望澄清此错误的原因以及如何正确编写 Cython 包装器。

最佳答案

您的主要问题是 the code in __init__.so (generated from __init__.pyx) does not get executed unless you also have __init__.py (which does not get executed in this case) .因此,你可以通过制作一个空的__init__.py文件来解决这个问题。这一切感觉就像一个困惑的边缘案例。在您的原始代码中,永远不会将 MyVector 类添加到模块中,因此它无法找到您描述的错误。

您的其他问题的简短答案是:

  1. 否 - 不幸的是,没有构建模板化包装类的好方法。不过,您不需要为仅在 Cython 中使用的任何内容构建包装器类。

  2. 我认为这些最终会成为非常重要的答案,因此我将跳过它们。一般而言,setup.py 似乎比 pyximport 更受青睐,文档中提供了有关如何使用它的很好示例。

  3. Cython 在内部跟踪对象的类型。每当它知道它正在使用指针和 时替换 -> 是相当简单的。 否则,正如您所说,您不必自己这样做。

关于python - 从 Cython 模块导出包装的 C++ 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33995063/

相关文章:

C++ SWIG 生成的代码取决于 Tcl

python - 了解如何为 numpy reshape() 指定新的形状参数

Python/WebApp Google App Engine - 测试用户/通过 header

c++ - 关于C/C++静态库的推理

c++ - 如何创建消息类型的数组

桌面应用程序的 Webkit 包装器

c# - ObjectSet 包装器不适用于 linqToEntities 子查询

python - 允许通过 Django 管理将 SVG 文件上传到 ImageField

python - 有没有办法改变散点图上的原点轴(零线)?

c++ - CORBA omniORB 在解析名称上下文后无法获取远程对象