Запустить Python класс из кода C++

288 просмотра
0
0 Комментариев

Добрый день.

Допустим что объявлен простой класс на языке python в файле example.py.

example.py

class point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
 
    def print_position(self):
        return "X: {0} Y: {1}\n".format(self.x, self.y)

Как вызвать метод print_position из кода написанного на C++?

main.cpp

#include<python2.7/Python.h>
#include <boost/python.hpp>
 
int main()
{
     Py_Initialize();
     ... CODE HERE
     Py_Finalize();
}

Смотрел в сторону Cyhton и boost.python но точно разобраться не получилось.
Ссылки в которых что-то нашел:


Добавить комментарий

2 Answers

Python Опубликовано 16.12.2018
0

Отсюда (с небольшими правками под Python 3.5 и дополнительными проверками)

#include <Python.h>
 
int main(int argc, char *argv[]) {
    PyObject *pName, *pModule, *pDict, *pClass, *pInstance, *pValue;
    int i, arg[8];
 
    if (argc < 4) {
        fprintf(stderr, "Usage: call module_name class_name method_name [arguments]\n");
        return 1;
    }
 
    Py_Initialize();
 
    // Преобразуем первый аргумент в unicode-строку python
    pName = PyUnicode_DecodeFSDefault(argv[1]);
    // Импортируем модуль
    // import module_name
    pModule = PyImport_Import(pName);
    Py_DECREF(pName);   // Освобождаем ссылку на строку с именем модуля
 
    if (pModule != NULL) {
        // Получаем пространство имён (__dict__) модуля
        pDict = PyModule_GetDict(pModule);
 
        // Получаем класс class_name
        pClass = PyDict_GetItemString(pDict, argv[2]);
 
        // Проверяем, что полученный class_name можно вызвать
        if (pClass && PyCallable_Check(pClass)) {
            // Получаем объект
            // obj = class_name()
            pInstance = PyObject_CallObject(pClass, NULL);
 
            if(pInstance != NULL) {
                // Подготавливаем параметры
                if(argc > 4) {
                    for (i = 0; i < argc - 4; i++) {
                        arg[i] = atoi(argv[i + 4]);
                    }
                    // Вызываем метод с двумя параметрами
                    // value = obj.multiply2(3, 2)
                    pValue = PyObject_CallMethod(pInstance, argv[3], "(ii)", arg[0], arg[1]);
 
                }
                else {
                    // Вызываем метод без параметров
                    // value = obj.multiply()
                    pValue = PyObject_CallMethod(pInstance, argv[3], NULL);
                }
 
                if (pValue != NULL) {
                    printf("Return of call : %d\n", PyLong_AsLong(pValue));
                    // Освобождаем ссылку на выделенную в памяти
                    // переменную для возвращённого из метода результата
                    Py_DECREF(pValue);
                }
                else {
                    PyErr_Print();
                }
 
                Py_DECREF(pInstance); // Освобождаем ссылку на объект
            }
            else {
                PyErr_Print();
            }
 
            Py_DECREF(pClass); // Освобождаем ссылку на класс
        }
        else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find class \"%s\"\n", argv[2]);
        }
 
        Py_DECREF(pDict); // Освобождаем ссылку на пространство имён
        Py_DECREF(pModule); // Освобождаем ссылку на модуль
    }
    else {
        PyErr_Print();
    }
 
    Py_Finalize();
 
    return 0;
}

Как заметил @jfs, это только пример, код сильно упрощён для ясности. В боевом проекте на те же операции будет раза в два больше кода. Или в четыре, если понадобится многопоточность.

Добавить комментарий
0

При ответе на вопрос очень помогли ответы выше и ответы по ссылке.

Структура проекта следующая: в одной папке лежат файлы main.cpp и example.py.

Файл example.py

class point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def print_position(self):
        return "X: {0} Y: {1}\n".format(self.x, self.y)

[/apcode]

Файл main.cpp:

#include 
#include 
#include 
//#include 
int main(int argc, char* argv[])
{
    Py_Initialize();
    // Для импорта созданного мною модуля необходимо передать
    // его имя как аргумент командной строки (у меня example.py)
    PySys_SetArgv(argc, argv);
    PyObject* module_name = PyString_FromString("example");
    // Загрузка модуля (example.py)
    PyObject* module = PyImport_Import(module_name);
    if (module == nullptr)
    {
        PyErr_Print();
        std::cerr << "Failed to import module\n";
        return 1;
    }
    // Загрузка пространств имен модуля
    PyObject* dict = PyModule_GetDict(module);
    if (dict == nullptr)
    {
        PyErr_Print();
        std::cerr << "Failed to import __dict__\n";
        return 1;
    }
    // Загрузка класса из example.py
    std::string py_class_name = "point";
    PyObject* py_class = PyDict_GetItemString(dict, py_class_name.c_str());
    if(py_class == nullptr)
    {
        PyErr_Print();
        std::cerr << "Failed import class " << py_class_name << std::endl;
        return 1;
    }
    // Поскольку конструктор принимает пару аргументов
    // То необходимо создать пару аргументов
    PyObject* py_arg_tuple = PyTuple_New(2);
    PyTuple_SetItem(py_arg_tuple, 0, PyInt_FromLong(5));
    PyTuple_SetItem(py_arg_tuple, 1, PyInt_FromLong(10));
    // Создание объекта класса point
    PyObject* obj;
    if (PyCallable_Check(py_class))
        obj = PyObject_CallObject(py_class, py_arg_tuple);
    else
        std::cout << "Cannot instantiate the Python class" << std::endl;
    // Вызываем метод print_position класса point
    PyObject* val = PyObject_CallMethod(obj, "print_position", NULL);
    if (!val)
        PyErr_Print();
    // конвертируем результат в std::string и печатаем
    std::string s (PyString_AsString(val));
    std::cout << s;
    Py_Finalize();
    return 0;
}

[/apcode]

Для запуска под ubuntu в консоли необходимо ввести команды:

$ g++ main.cpp -std=c++11 -lpython2.7
$ ./a.out example

P.S. аргумет командной строки совпадает с названием импортируемого и написанного мною pyhton модуля.

Добавить комментарий
Напишите свой ответ на данный вопрос.
Scroll Up