c++ - 如何在 Python ctypes 中处理 C++ 返回类型 std::vector<int>?

标签 c++ python ctypes

我找不到 ctypes 如何弥合 std::vector 和 Python 之间的差距;互联网上没有提到的组合。这是不好的做法,它不存在还是我遗漏了什么?

C++ : xxx.cpp

#include <fstream>
#include <string>
using namespace std;
extern "C" std::vector<int> foo(const char* FILE_NAME)
{
    string line;
    std::vector<int> result;
    ifstream myfile(FILE_NAME);
    while (getline(myfile, line)) {
      result.push_back(1);
    }

    return(result);
}

Python: xxx.py

import ctypes
xxx = ctypes.CDLL("./libxxx.so")
xxx.foo.argtypes = ??????
xxx.foo.restype = ??????

最佳答案

无论这种方法是否真的提供了更快的执行时间,我都会稍微解释一下您可以如何去做。基本上,创建一个指向 C++ vector 的指针,它可以通过 C 函数与 Python 交互。然后,您可以将 C++ 代码包装在 Python 类中,隐藏 ctypes 的实现细节。

我将我认为有用的魔术方法包含在 Python 类中。您可以选择删除它们或添加更多以满足您的需要。不过,析构函数很重要。

C++

// vector_python.cpp
#include <vector>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

extern "C" void foo(vector<int>* v, const char* FILE_NAME){
    string line;
    ifstream myfile(FILE_NAME);
    while (getline(myfile, line)) v->push_back(1);
}

extern "C" {
    vector<int>* new_vector(){
        return new vector<int>;
    }
    void delete_vector(vector<int>* v){
        cout << "destructor called in C++ for " << v << endl;
        delete v;
    }
    int vector_size(vector<int>* v){
        return v->size();
    }
    int vector_get(vector<int>* v, int i){
        return v->at(i);
    }
    void vector_push_back(vector<int>* v, int i){
        v->push_back(i);
    }
}

将其编译为共享库。在 Mac OS X 上,这可能看起来像,

g++ -c -fPIC vector_python.cpp -o vector_python.o
g++ -shared -Wl,-install_name,vector_python_lib.so -o vector_python_lib.so vector_python.o

python

from ctypes import *

class Vector(object):
    lib = cdll.LoadLibrary('vector_python_lib.so') # class level loading lib
    lib.new_vector.restype = c_void_p
    lib.new_vector.argtypes = []
    lib.delete_vector.restype = None
    lib.delete_vector.argtypes = [c_void_p]
    lib.vector_size.restype = c_int
    lib.vector_size.argtypes = [c_void_p]
    lib.vector_get.restype = c_int
    lib.vector_get.argtypes = [c_void_p, c_int]
    lib.vector_push_back.restype = None
    lib.vector_push_back.argtypes = [c_void_p, c_int]
    lib.foo.restype = None
    lib.foo.argtypes = [c_void_p]

    def __init__(self):
        self.vector = Vector.lib.new_vector()  # pointer to new vector

    def __del__(self):  # when reference count hits 0 in Python,
        Vector.lib.delete_vector(self.vector)  # call C++ vector destructor

    def __len__(self):
        return Vector.lib.vector_size(self.vector)

    def __getitem__(self, i):  # access elements in vector at index
        if 0 <= i < len(self):
            return Vector.lib.vector_get(self.vector, c_int(i))
        raise IndexError('Vector index out of range')

    def __repr__(self):
        return '[{}]'.format(', '.join(str(self[i]) for i in range(len(self))))

    def push(self, i):  # push calls vector's push_back
        Vector.lib.vector_push_back(self.vector, c_int(i))

    def foo(self, filename):  # foo in Python calls foo in C++
        Vector.lib.foo(self.vector, c_char_p(filename))

然后您可以在解释器中对其进行测试(file.txt 仅包含三行乱码)。

>>> from vector import Vector
>>> a = Vector()
>>> a.push(22)
>>> a.push(88)
>>> a
[22, 88]
>>> a[1]
88
>>> a[2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "vector.py", line 30, in __getitem__
    raise IndexError('Vector index out of range')
IndexError: Vector index out of range
>>> a.foo('file.txt')
>>> a
[22, 88, 1, 1, 1]
>>> b = Vector()
>>> ^D
destructor called in C++ for 0x1003884d0
destructor called in C++ for 0x10039df10

关于c++ - 如何在 Python ctypes 中处理 C++ 返回类型 std::vector<int>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16885344/

相关文章:

python - 是否有在 cygwin 上安装 Kivy 的说明?

c++ - 在 python 中嵌入 c++ 代码会让你的 python 应用程序更快吗?

c++ - 在 C++ 中使用 STL 生成成对项目的 vector

python - 在python中调整4维数组的图像大小

python - Winmm.dll 不返回文件长度

python - 如何聚合这些数据并使用 python 和 pandas 创建一个新列?

python - 计算 Vandermonde 矩阵的有效方法

c++ - MFC 对话框返回 vector

c++ - 如何将对象的属性复制到 vector ?

c++ - 返回链表中值的总和