Как организовать передачу python функции в С++ класс для выполнения callback через интерфейс SWIG?

Рейтинг: 0Ответов: 1Опубликовано: 17.03.2015

Здравствуйте! У меня есть класс нейронной сети на С++. На каждой итерации обучения нужно организовать передачу сообщения о прогрессе в GUI класс на Python3 через интерфейс SWIG. GUI создано при помощи PyQt4. Как выполнить callback правильно? Пробовал так.

Взял пример отсюда. Загрузить одним файлом можно здесь. Захожу в папку swig-examples/python/callback/ создаю каталог /bin/examples. Захожу в этот каталог и даю команду:

$make -f ../../Makefile

В результате:

make -f ../../Makefile  CXXSRCS='example.cxx' SWIG='swig' \
SWIGOPT='' TARGET='example' INTERFACE='example.i' python_cpp
make[1]: вход в каталог «/home/serg/callback/bin/debug»
make[1]: *** Нет правила для сборки цели «python_cpp».  Останов.
make[1]: выход из каталога «/home/serg/callback/bin/debug»
../../Makefile:13: ошибка выполнения рецепта для цели «build»
make: *** [build] Ошибка 2

Помогите!!!

Ответы

▲ 1Принят

Нашел более-менее рабочее решение при помощи Python.h. Не знаю, насколько это грамотно, если кто разбирается, поправьте, пожалуйста.

В первом файле описан класс-обертка над PyObject - функцией или объектом Python.

cregister.cpp

#include <python3.4/Python.h>
#include <stdlib.h>
/***********************************************/
/* 1) code to route events to Python object    */
/* note that we could run strings here instead */
/***********************************************/
class Caller{

private:

PyObject*  Route_Event(int count)

{
    PyObject *args, *pres;
    /* call Python handler */
    args = Py_BuildValue("(i)", count);   /* make arg-list */
    pres = PyEval_CallObject(Handler, args);      /* apply: run a call */
    return pres;
}
public:
  PyObject *Handler;     /* keep Python object in C */
  Caller()
  {
    Handler = NULL;     /* keep Python object in C */    
  }

/*****************************************************/
/* 2) python extension module to register handlers   */
/* python imports this module to set handler objects */
/*****************************************************/
void setHandler(PyObject *arg)
{
    /* save Python callable object */
    Handler = arg;
    //Py_XDECREF(Handler);                 /* called before? */
    //PyArg_Parse(arg, "(O)", &Handler);  /* one argument */
    //Py_XINCREF(Handler);                 /* add a reference */
}
void triggerEvent(int arg)
{
    /* let Python simulate event caught by C */
    Route_Event(arg);
}
};

Второй файл - интерфейс для swig:

cregister.i

%module cregister
%{
#include "cregister.cpp"
%}
%include cregister.cpp

makefile для того чтобы собрать все это:

makefile

PYLIB = /usr/local/bin
PYINC = /usr/include/python3.4

CMODS = _cregister.so
CFLAGS = -O3 -fopenmp
all: $(CMODS) cregister.py

# обертка + действительный класс
$(CMODS): cregister_wrap.o cregister.o
     g++ $(CFLAGS) -shared cregister_wrap.o cregister.o  -L $(PYLIB) -o $@
# генерирует модуль обертки класса
cregister_wrap.o: cregister_wrap.cxx
 g++ $(CFLAGS) cregister_wrap.cxx -c -g -fPIC -I $(PYINC) 
cregister_wrap.cxx: cregister.i
 swig -c++ -python cregister.i
cregister.py: cregister.i
 swig -c++ -python cregister.i

# программный код обертки класса C++
cregister.o:
    g++ $(CFLAGS) ../wavenet/cregister.cpp -c -g -fPIC -Wno-deprecated

clean:

    rm -f *.pyc *.o *.so *.cxx cregister.py

Ну и наконец иллюстрация на Python3:

creg.py

#! /usr/bin/python3
"""
#########################################################################
in Python, register for and handle event callbacks from the C language;
compile and link the C code, and launch this with 'python3 creg.py'

######################################################################### """

####################################
# C calls these Python functions;
# handle an event, return a result
####################################
class Caller(object):
    def __init__(self, str):
        self.str=str
    def __call__(self, count):
       print(self.str.format(count))

#######################################
# Python calls a C extension module
# to register handlers, trigger events
#######################################
import sys
sys.path.append('you_bin_path/')
import cregister
cal = Caller("Helllo{0}")
cb = cregister.Caller()
print('\nTest1:')
cb.setHandler(cal)      # register callback function

for num in range(1, 10):
    res = cb.triggerEvent(num)         # simulate events caught by C layer