C++ vector to Python 3.3

C++ vector to Python 3.3

本文关键字:Python to vector C++      更新时间:2023-10-16

我想从c++脚本中获得一个python列表,例如,[1,2,3,4]。我编写了c++脚本,它返回一个向量。

如何连接两端没有SWIG/SIP/Cython/和其他?

是否可以更容易地将c++编译为。exe或elf文件,然后从命令行调用,让。exe创建一个包含矢量的。txt并使用python读取它?

我的观点是,我只需要c++中的一个非常小的函数来对大数据进行繁重的计算。要做到这一点,最不痛苦、最短的方法是什么?

编辑:

举个例子。Python将给c++提供一个文件名字符串("foo.txt"),然后它将读取文件的上下文(200,000行乘300列),计算缺失的数量,然后将每行缺失的数量返回给Python。这将产生一个包含200,000个数字的列表。他们之间如何进行这种沟通?

为了完整起见,这是我仍然想知道如何去做的事情:

  • 将python文件名字符串传递给c++
  • 接收c++ python字符串
  • 在c++中创建矢量
  • 返回Python
  • Python中的接收向量

这现在可能是没有意义的,我在你的其他问题上发布了类似的东西,但我已经为Python 3.3和c++改编了这个版本,而不是Python 2.7和C。

如果你想返回一个Python列表对象,并且由于你正在构建一个可能非常长的列表(200,000项),那么在c++代码中构建Python列表可能更有效,而不是构建std::vector然后稍后将其转换为Python列表。

根据你其他问题中的代码,我建议使用这样的代码…

// foo.cpp
#include <python3.3/Python.h>
#include <fstream>
#include <string>
using namespace std;
extern "C"
{
    PyObject* foo(const char* FILE_NAME)
    {
        string line;
        ifstream myfile(FILE_NAME);
        PyObject* result = PyList_New(0);
        while (getline(myfile, line))
        {
            PyList_Append(result, PyLong_FromLong(1));
        }
        return result;
    }
}

编译与…

$ g++ -fPIC -shared -o foo.so foo.cpp -lpython3.3m

…还有一个用法的例子…

>>> from ctypes import *
>>> foo = CDLL('./foo.so')
>>> foo.foo.restype = py_object
>>> foo.foo(b'foo.cpp')
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

…虽然如果您需要将现有的std::vector转换为Python列表,您可以通过将向量的长度传递给PyList_New()来预先分配Python列表所需的内存,然后使用PyList_SetItem()而不是PyList_Append()

我能想到的唯一其他方法是…

  1. 在Python中预先分配一块RAM,并让c++函数填充值,就像在qarma的答案中一样,但您必须事先知道要分配多少RAM。您可以选择一个任意的值,但是考虑到文件中的行数事先不知道,这个数字可能太大或太小。

  2. 在c++中堆分配std::vector,并返回指向第一个元素的指针,以及元素的数量,但是你必须写第二个函数来释放RAM,一旦你完成了它。

无论哪种方式,您仍然有将'返回'数组转换为Python列表的开销,因此您不妨自己完成。

定义您的入口点extern "C"并使用ctypes

下面是一个示例,数据从Python传递,c++代码对数据进行排序,然后Python返回结果:

#include <sys/types.h>
#include <algorithm>
extern "C" {
    void foo(float* arr, size_t len);
}
void foo(float* arr, size_t len)
{
    // if arr is input, convert to C++ array
    // crazy C++ code here
    std::sort(arr, arr+len);
    // if arr is output, convert C++ array to arr
}

编译你的代码到一个共享对象(libxxx. exe)。linux上是libxxx.dll, win上是libxxx.dll。),然后动态加载它,并通过ctypes传入/传出数据:

import ctypes
import posix
# Darwin .dylib; Linux .so; Windows .dll; use sys.platform() for runtime detection
libxxx = ctypes.CDLL("./libxxx.so")
libxxx.foo.argtypes = [ctypes.POINTER(ctypes.c_float), ctypes.c_size_t]
libxxx.foo.restype = None
data = ctypes.ARRAY(ctypes.c_float, 100)()
# write someting into data[x]
import random
for i in range(100): data[i] = random.random()
print data[:3], "...", data[-3:]
libxxx.foo(data, len(data))
# read out from data[x]
print data[:3], "...", data[-3:]

ctypes的伟大之处在于它从2.5开始就与Python捆绑在一起了,你不需要任何额外的库。

如果你想使用更高级的东西,看看cffi

你做对了。

你有两个可执行文件吗?

最好将其保存到中间文件中。锁定文件,从c++代码中写入文件。解锁并从Python中读取。

如果你只是想从python运行,你可以考虑扩展python:

用c++扩展Python

也可以选择通过套接字来传递,但是如果您只想传递列表,那么这可能有点多余。

您可以使用python中的subprocess模块从c++ exe文件中读取输出。例如:

c++文件:

#include <iostream>
using namespace std;
int main()
{
    int a[]={1,2,3,4};
    cout<<"[";
    for(int i=0; i<3; i++)
        cout<<a[i]<<",";
    cout<<a[3]<<"]";
    return 0;
}

那么你的python脚本将是:

import subprocess
a=subprocess.check_output("c++compiledfile")
l=eval(a)
print l

你可以在进程间通信中使用字符串:
使用Python中的subprocess.check_output()函数来检查c++程序的输出,并将文件名作为参数传递:

Python代码:

import subprocess
from time import clock

ti=clock()
txt_fname='foo.txt'
# pass the filename string to a c++ program, and receive vector in python
output=subprocess.check_output(["./prog", txt_fname])
result = eval(output)   # convert the str_result to a vector/list
tf=clock()
print(result)
print(format(tf-ti, '.3f'))
c++代码:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>

int main(int argc, char *argv[])
{
    // receive python string in c++
    char* txt_fname = argv[1];
/*  // read matrix from file in c++
    FILE *f_matrix = fopen(txt_fname, "r");
    // ... [done by the question's author!]
    if (f_matrix!=NULL){
        fclose(f_matrix);
    }*/
    // create the vector in c++
    int n=200000;
    std::vector<int> vect(n);
    // or:  int vect[];
    // ... [done by the question's author!]
    // return the vector to python
    std::cout << "[";
    for (int i=0; i<n; i++)
        std::cout << vect[i] << ", ";
    std::cout << "]";
    return 0;
}

EDIT:添加计时器并将"ast.literal_eval()"替换为"eval()",因为实际上eval()在这种情况下更快,并且与python 3.3兼容。