繁体   English   中英

将python函数传递给SWIG包装的C ++代码

[英]Passing python functions to SWIG wrapped C++ code

我正在尝试使用SWIG为python包装一个C ++库。 该库经常使用回调函数,通过将特定类型的回调函数传递给类方法。

现在,在包装代码之后,我想从python创建回调逻辑。 这可能吗? 这是我正在做的一个实验来找出它..目前不起作用。

标头和swig文件如下:

paska.h:

typedef void (handleri)(int code, char* codename);

// handleri is now an alias to a function that eats int, string and returns void

void wannabe_handleri(int i, char* blah);

void handleri_eater(handleri* h);

paska.i:

%module paska

%{ // this section is copied in the front of the wrapper file
#define SWIG_FILE_WITH_INIT
#include "paska.h"
%}

// from now on, what are we going to wrap ..

%inline %{
// helper functions here

void wannabe_handleri(int i, char* blah) {
};

void handleri_eater(handleri* h) {
};

%}

%include "paska.h"

// in this case, we just put the actual .cpp code into the inline block ..

最后,我在python中测试..

import paska

def testfunc(i, st):
  print i
  print st

paska.handleri_eater(paska.wannabe_handleri(1,"eee")) # THIS WORKS!

paska.handleri_eater(testfunc) # THIS DOES NOT WORK!

最后一行抛出“TypeError:in method'handri_eater',参数1'类型'handleri *'”

有没有办法将python函数“强制转换”为SWIG包装器接受的类型?

在我看来, ctypes和SWIG类型typemap的组合将是解决问题的最简单方法。 ctypes可以很容易地生成一个调用Python可调用的C函数。 Python代码应该是这样的:

import example

# python callback
def py_callback(i, s):
    print( 'py_callback(%d, %s)'%(i, s) )

example.use_callback(py_callback)

在SWIG方面,我们有:(1)Python函数use_callback ,它使用ctypes包装器包装Python回调,并将包装器的地址作为整数传递给_example.use_callback() ,以及(2)SWIG类型typemap ,提取地址并将其转换为适当的函数指针。

%module example

// a typemap for the callback, it expects the argument to be an integer
// whose value is the address of an appropriate callback function
%typemap(in) void (*f)(int, const char*) {
    $1 = (void (*)(int i, const char*))PyLong_AsVoidPtr($input);;
}

%{
    void use_callback(void (*f)(int i, const char* str));
%}

%inline
%{

// a C function that accepts a callback
void use_callback(void (*f)(int i, const char* str))
{
    f(100, "callback arg");
}

%}

%pythoncode
%{

import ctypes

# a ctypes callback prototype
py_callback_type = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)

def use_callback(py_callback):

    # wrap the python callback with a ctypes function pointer
    f = py_callback_type(py_callback)

    # get the function pointer of the ctypes wrapper by casting it to void* and taking its value
    f_ptr = ctypes.cast(f, ctypes.c_void_p).value

    _example.use_callback(f_ptr)

%}

您可以在此处找到包含CMakeLists.txt文件的完整示例。

编辑:合并@Flexo建议将Python部分移动到SWIG文件的%pythoncode块中。

编辑:合并@ user87746建议Python 3.6+兼容性。

您可以使用“director”在Python中实现回调逻辑。

基本上,不是传递回调函数,而是传递回调对象。 基础对象可以在C ++中定义,并提供virtual回调成员函数。 然后可以继承此对象,并在Python中覆盖回调函数。 然后可以将继承的对象传递给C ++函数而不是回调函数。 为此,您需要为此类回调类启用导演功能。

但这确实需要更改底层C ++库。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM