C ++ вектор на Python 3.3

Я хотел бы получить список Python, скажем, [1,2,3,4]из сценария C ++. Я написал скрипт C ++, который возвращает вектор.

Как соединить концы без SWIG / SIP / Cython / и других?

Может быть проще просто скомпилировать C ++ в файл .exe или elf, а затем вызвать из командной строки файл .exe, создать .txt, содержащий вектор, и прочитать его с помощью python?

Суть в том, что мне нужна действительно маленькая функция из C ++, чтобы выполнять тяжелые вычисления с большими данными. Что было бы наименее болезненным и самым коротким способом сделать это?

РЕДАКТИРОВАТЬ:
Чтобы привести пример. Python передаст строку имени файла в C ++ («foo.txt»), который затем прочитает контекст файла (200 000 строк на 300 столбцов), посчитает пропуски и затем вернет Python количество пропущений в строке. Это дает список 200 000 номеров.
Как это общение между ними?

Просто для полноты, это то, что я все еще задаюсь вопросом о том, как это сделать:

  • Передать строку имени файла Python в C ++
  • Получить строку Python в C ++
  • Совершено Создание вектора в C ++
  • Вернуть вектор в Python
  • Получить вектор в Python

8

Решение

Это, вероятно, спорный, и я отвечал что-то похожее на ваш другой вопрос, но я адаптировал эту версию для Python 3.3 и C ++, а не Python 2.7 и C.

Если вы хотите получить обратно объект списка Python, и поскольку вы создаете список, который потенциально может быть очень длинным (200 000 элементов), вероятно, более эффективно построить список Python в коде C ++, а не создавать 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, вы можете предварительно выделить память, необходимую для списка Python, передав длину вектора в PyList_New(), а затем использовать PyList_SetItem() вместо PyList_Append().

Единственные другие методы, о которых я могу думать, были бы …

  1. Чтобы предварительно выделить блок оперативной памяти в Python и заставить функцию C ++ заполнять значения, как в ответе qarma, вам нужно заранее знать, сколько оперативной памяти выделить. Вы можете просто выбрать произвольное значение, но, учитывая, что количество строк в файле заранее неизвестно, это число может быть слишком большим или слишком маленьким.

  2. Чтобы куча-выделить std::vector в C ++ и возвращает указатель на первый элемент и количество элементов, но вам нужно написать вторую функцию, чтобы освободить ОЗУ, как только вы покончили с этим.

В любом случае, у вас все еще есть издержки на преобразование возвращаемого массива в список Python, так что вы можете сделать это самостоятельно.

5

Другие решения

Определите вашу точку входа 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.so в linux, libxxx.dll в win, libxxx.dylib в osx), затем загрузите его динамически и передавайте / выводите данные через 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 в том, что он поставляется с Python начиная с 2.5, вам не нужны никакие дополнительные библиотеки.

Если вы хотите использовать что-то более продвинутое, взгляните на cffi,

6

Вы на правильном пути.

У тебя есть два исполняемых файла?

Лучше было бы сохранить его в промежуточный файл. Заблокируйте файл, запишите в него код C ++. Разблокируйте и прочитайте его из Python.

Если вы просто хотите запустить из Python, вы всегда можете посмотреть на расширение Python:

Расширение Python с помощью C ++

Есть также возможность сделать это через сокеты, хотя это может быть немного излишним, если все, что вы хотите сделать, это пропустить списки.

3

Вы можете использовать модуль подпроцесса в python для чтения вывода из вашего exe-файла c ++.
Например:

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
3

Вы можете работать со строками в межпроцессном взаимодействии:

используйте функцию subprocess.check_output () в Python, чтобы проверить вывод программы C ++ и передать имя файла в качестве аргумента:

Код Python:

import subprocess
from time import clockti=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;
}

РЕДАКТИРОВАТЬ: добавить таймеры и заменить «ast.literal_eval ()» на «eval ()», потому что на самом деле eval () в этом случае быстрее и совместим с python 3.3.

0
По вопросам рекламы [email protected]