Cython扩展类:如何在自动生成的C结构中公开方法? [英] Cython extension class: How do I expose methods in the auto-generated C struct?

查看:88
本文介绍了Cython扩展类:如何在自动生成的C结构中公开方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我现有的C ++代码定义了一些我需要使用的类,但是我需要能够将这些类发送给Python代码。具体来说,我需要在C ++中创建类实例,创建Python对象以用作这些C ++对象的包装,然后将这些Python对象传递给Python代码进行处理。这只是一个较大的C ++程序的一部分,因此最终需要使用C / Python API在C ++中完成。

I have existing C++ code that defines some classes I need to use, but I need to be able to send those classes to Python code. Specifically, I need to create class instances in C++, create Python objects to serve as wrappers for these C++ objects, then pass these Python objects to Python code for processing. This is just one piece of a larger C++ program, so it needs to be done ultimately in C++ using the C/Python API.

为了让我的生活更轻松,使用Cython定义扩展类(cdef类),这些扩展类用作我的C ++对象的Python包装器。我使用的典型格式是cdef类包含一个指向C ++类的指针,然后在创建cdef类实例时对其进行初始化。由于如果我要包装现有的C ++对象,我也希望能够替换该指针,因此我已将我的cdef类中的方法添加到了C ++对象 accept()和抓住它的指针。我的其他cdef类在Cython中成功使用了 accept()方法,例如,当一个对象拥有另一个对象时。

To make my life easier, I have used Cython to define extension classes (cdef classes) that serve as the Python wrappers for my C++ objects. I am using the typical format where the cdef class contains a pointer to the C++ class, which is then initialized when the cdef class instance is created. Since I also want to be able to replace the pointer if I have an existing C++ object to wrap, I have added methods to my cdef classes to accept() the C++ object and take its pointer. My other cdef classes successfully use the accept() method in Cython, for example when one object owns another.

这是我的Cython代码的示例:

Here is a sample of my Cython code:

MyCPlus.pxd

cdef extern from "MyCPlus.h" namespace "mynamespace":
    cdef cppclass MyCPlus_Class:
        MyCPlus_Class() except +

PyModule.pyx

cimport MyCPlus
from libcpp cimport bool

cdef class Py_Class [object Py_Class, type PyType_Class]:
    cdef MyCPlus.MyCPlus_Class* thisptr
    cdef bool owned

    cdef void accept(self, MyCPlus.MyCPlus_Class &indata):
        if self.owned:
            del self.thisptr
        self.thisptr = &indata
        self.owned = False

    def __cinit__(self):
        self.thisptr = new MyCPlus.MyCPlus_Class()
        self.owned = True

    def __dealloc__(self):
        if self.owned:
            del self.thisptr

当我尝试从C ++访问 accept()方法时,问题就来了。我尝试在我的cdef类和 accept()上使用 public api 关键字方法,但是我无法弄清楚如何在Cython自动生成的 .h 文件的C结构中公开此方法。不管我尝试什么,C结构看起来都是这样:

The problem comes when I try to access the accept() method from C++. I tried using the public and api keywords on my cdef class and on the accept() method, but I cannot figure out how to expose this method in the C struct in Cython's auto-generated .h file. No matter what I try, the C struct looks like this:

PyModule.h (由Cython自动生成)

PyModule.h (auto-generated by Cython)

struct Py_Class {
  PyObject_HEAD
  struct __pyx_vtabstruct_11PyModule_Py_Class *__pyx_vtab;
  mynamespace::MyCPlus_Class *thisptr;
  bool owned;
};

我也尝试输入 self 输入为 Py_Class ,我什至尝试与 public Py_Class $ c>和 api 关键字。我还尝试过将 accept()设为静态方法。我没有尝试过公开 accept()方法,以便可以在C ++中使用它。我确实尝试通过 __ pyx_vtab 访问它,但出现编译器错误,无效使用不完整类型。我已经搜索了很多,但是还没有找到解决方案。谁能帮我?

I also tried typing the self input as a Py_Class, and I even tried forward-declaring Py_Class with the public and api keywords. I also experimented with making accept() a static method. Nothing I've tried works to expose the accept() method so that I can use it from C++. I did try accessing it through __pyx_vtab, but I got a compiler error, "invalid use of incomplete type". I have searched quite a bit, but haven't seen a solution to this. Can anyone help me? Please and thank you!

推荐答案

正如您在注释中公开我的方法,看来 __pyx_vtab 成员仅供Cython使用,因为它甚至都没有在导出的标头中为其定义结构类型。

As you pointed in your comment, it does seem that the __pyx_vtab member is for Cython use only, since it doesn't even define the struct type for it in the exported header(s).

除了您的响应外,一种方法还可能是:

Adding to your response, one approach could also be:

cdef api class Py_Class [object Py_Class, type Py_ClassType]:
    ...
    cdef void accept(self, MyCPlus.MyCPlus_Class &indata):
        ...  # do stuff here
    ...


cdef api void (*Py_Class_accept)(Py_Class self, MyCPlus.MyCPlus_Class &indata)
Py_Class_accept = &Py_Class.accept

基本上,我们定义一个函数指针并将其设置为我们要公开的扩展方法。这与您响应的 cdef d函数没有多大区别;主要区别在于,我们可以像平常一样在类定义中定义方法,而不必重复功能或对另一个函数的方法/函数调用以将其公开。需要注意的是,除了 self 的扩展类型(在这种情况下)等之外,我们还必须几乎完全定义函数指针的签名,而该签名完全是方法的签名。然后再次适用于常规函数。

Basically, we define a function pointer and set it to the extension's method we want to expose. This is not that much different to your response's cdef'd function; the main difference would be that we can define our methods as usual in the class definition without having to duplicate functionality or method/function calls to another function to expose it. One caveat is that we would've to define our function pointer's signature almost verbatim to the method's one in addition to the self's extension type (in this case) and etc; then again this also applies for regular functions.

请注意,我在C级Cython .pyx 文件,我没有,也没有打算在CPP实施文件上对其进行测试。但我想,希望这可能同样有用。

Do note that I tried this up on a C-level Cython .pyx file, I haven't and do not intent to test it on a CPP implementation file. But hopefully this might work just as fine, I guess.

这篇关于Cython扩展类:如何在自动生成的C结构中公开方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆