繁体   English   中英

使用Cython在C ++中使用Python代码中的数据

[英]Using data in Python code from C++ using Cython

我正在尝试使用Cython从我的Python代码中的C ++代码获取列表。

这是我的标头(例如h):

namespace c                   
{                             
class C {                     
    int id;                   
public:                       
    C(int id) {               
        this->id = id;        
    }                         
    int getId();              
};                            
typedef std::vector<C> CList; 
}       

和我的源文件(ex.cpp):

namespace c                      
{                                
int C::getId() {                 
    return this->id;             
}                                
CList getlist(int t) {           
    CList list;                  
    for (int i = 0; i < t; ++i) {
        C c(i);                  
        list.push_back(c);       
    }                            
    return list;                 
}                                
}                                

所以在我的Python代码中,我想像这样遍历CList:

import exapi               

for i in exapi.take_list():
    print i               
    # OR
    print i.get_id()

在.pyx文件(exapi.pyx)中,我试图创建Cython扩展名来处理C ++对象:

cdef extern from "ex.h" namespace "c":        
    cdef cppclass C:                          
        C(int) except +                       
        int getId()                           

    cdef cppclass CList:                      
        pass                                  

    cdef CList getlist(int)                   

cdef class PY_C:                              
    pass                                      

cdef class PY_CList:                          
    pass                                      


def take_list():                              
    return getlist(10) # I know this is wrong 

我应该在PY_C和PY_Clist中添加哪些转发方法和功能,以使python代码正常工作?

我读了Cython中的Using C ++ ,但是在Cython代码中创建了新对象,但就我而言,我需要使用在C ++端创建的对象。

尝试解决这个问题时,我重写了一些示例,但是原则上您给的与我给的没有区别。

我也更改了一些名称,因为示例名称对我来说太短了;)。

cobject.hpp

#include <vector>

namespace cobject {
    class CObject {
        int id;
    public:
        CObject(int id): id(id) {}
        int getId();
    };

    typedef std::vector<CObject> CObjectList;
    CObjectList getlist(int t);
}

cobject.cpp

#include "cobject.hpp"

namespace cobject {
    int CObject::getId() {
        return this->id;
    }

    CObjectList getlist(int t) {
        CObjectList list;

        for (int i = 0; i < t; ++i) {
            list.push_back(CObject(i));
        }

        return list;
    }
}

这些并没有什么不同。

我想使用pyximport ,但是要在C ++中使用它,您需要一个特殊的文件:

cobject_api.pyxbld

import os
from distutils.extension import Extension

dirname = os.path.dirname(__file__)

def make_ext(modname, pyxfilename):
    return Extension(
        name=modname,
        sources=[pyxfilename, "cobject.cpp"],
        language="c++",
        include_dirs=[dirname]
    )

然后是魔术:

cython_api.pyx

from cython.operator cimport dereference as deref

cdef extern from "cobject.hpp" namespace "cobject":
    cdef cppclass CObject:
        CObject(int) except +
        int getId()

    cdef cppclass CObjectList:
        CObject &at(size_t)
        size_t size()

    cdef CObjectList getlist(int)


# Cython wrappers

cdef class PyCObject:
    cdef CObject *wrapped
    cdef object keepalive

    def __cinit__(self, keepalive):
        self.keepalive = keepalive

    property id:
        def __get__(self):
            return self.wrapped.getId()

    def __repr__(self):
        return "PyCObject({})".format(self.id)

cdef class PyCObjectList:
    cdef CObjectList wrapped

    def __iter__(self):
        cdef PyCObject pycobject

        cdef size_t idx = 0

        while idx < self.wrapped.size():
            pycobject = PyCObject(self)
            pycobject.wrapped = &self.wrapped.at(idx)

            yield pycobject

            idx += 1

def take_list():
    cdef PyCObjectList pycobjectlist = PyCObjectList()
    pycobjectlist.wrapped = getlist(10)

    return pycobjectlist

运行方式如下:

main.py

import pyximport
pyximport.install()

import cobject_api

for i in cobject_api.take_list():
    print("{} has id {}".format(i, i.id))

这个想法是您的包装器类拥有数据的所有权。 由于getlist是按值返回的,因此您必须对其进行复制,但是其他对象包装器可以使用指针。

与其使用CObjectList类型,还不如使用预包装的矢量类并对其进行迭代。 但是,除非您确实使用间接指针将所有内容保留在堆上,否则将它们包装起来不是很好。

这是因为您不能轻易地指向要保留在堆栈中的内容,而Cython如果想要与Python的垃圾收集器配合使用,则需要指向这些内容。 这就解释了代码中的keepalive变量的用途:与Python中删除向量不会影响其元素的方式不同,而在C ++中,删除向量不会影响其元素。 使用指针向量,可以缓解这些问题。

另请参阅此链接上的另一个问题。 提出了一些相同的观点,并给出了用于更传统设置的体系结构。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM