python - 带回调的 PyBindGen

标签 python c python-3.x callback pybindgen

我正在尝试使用 PyBindGen 为我的 C 库创建一个带有回调的 python 扩展模块。尽管PyBindGen frontpage说回调是一个缺失的特性,当前源代码和this discussionarchive有如何设置 PyBindGen 以将回调函数从 python 传递到 C 库的示例。

问题在于示例定义回调方法时将PyObject*作为void *参数携带回调函数指针信息。由于我的 API 没有这样的上下文指针,我试图在 C 绑定(bind)代码中保留对回调的引用 similar to standard python example .问题是我不知道如何让 PyBindGen 设置全局 PyObject * my_callback。我怎样才能做到这一点?这是我的代码

我的库头文件

typedef void (*CallbackType) (int value);
void register_cb(CallbackType cb);
void set_num(int n);

我的库源文件

#include "c.h"

static CallbackType cb_;
void register_cb(CallbackType cb)
{
    cb_ = cb;
}
void set_num(int n)
{
    cb_(n);
}

我的 PyBindGen modulegen.py 需要添加的注释部分到自动生成的代码以使其工作

import sys
import pybindgen
from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink
from pybindgen import CppMethod, CppConstructor, CppClass, Enum
from pybindgen.typehandlers.base import ForwardWrapperBase

class CallbackTypeParam(Parameter):

    DIRECTIONS = [Parameter.DIRECTION_IN]
    CTYPES = ['CallbackType']

    def convert_python_to_c(self, wrapper):
        assert isinstance(wrapper, ForwardWrapperBase)

        py_cb = wrapper.declarations.declare_variable("PyObject*", self.name)
        wrapper.parse_params.add_parameter('O', ['&'+py_cb], self.name)
        wrapper.before_call.write_error_check("!PyCallable_Check(%s)" % py_cb, """PyErr_SetString(PyExc_TypeError, "CallbackType parameter must be callable");""")

        #####
        # NEED TO INSERT THE FOLLOWING TWO LINES INTO AUTOGENERATED OUTPUT HERE
        #    Py_XDECREF(my_callback); // NEEDS TO BE AUTO-GENERATED !!!
        #    my_callback = cb;        // NEEDS TO BE AUTO-GENERATED !!!
        #####

        wrapper.call_params.append("_wrap_callback")
        wrapper.before_call.write_code("Py_INCREF(%s);" % py_cb)
        wrapper.before_call.add_cleanup_code("Py_DECREF(%s);" % py_cb)

    def convert_c_to_python(self, wrapper):
        raise NotImplementedError


def my_module_gen(out_file):

    mod = Module('c')
    mod.add_include('"c.h"')

    mod.header.writeln("""
void _wrap_callback(int value);
static PyObject *my_callback = NULL;
""")

    mod.body.writeln("""
void _wrap_callback(int value)
{
int arg;
PyObject *arglist;

arg = value;
printf("@@@@ Inside the binding: %d %p\\n", value, my_callback); fflush(NULL);

arglist = Py_BuildValue("(i)", arg);
PyObject_CallObject(my_callback, arglist);
Py_DECREF(arglist);
}
""")


    mod.add_function("register_cb", None, [Parameter.new("CallbackType", "cb")])
    mod.add_function("set_num", None, [Parameter.new("int", "n")])

    mod.generate(FileCodeSink(out_file))

if __name__ == '__main__':
    my_module_gen(sys.stdout)

我的用于构建扩展模块的 setup.py 文件

#!/usr/bin/env python
import os
from distutils.core import setup, Extension
from modulegen import my_module_gen as generate

try:
    os.mkdir("build")
except OSError:
    pass
os.environ["CC"] = "g++"
module_fname = os.path.join("build", "autogen-binding.c")
with open(module_fname, "wt") as file_:
    print("Generating file {}".format(module_fname))
    generate(file_)

mymodule = Extension('c',
                    sources = [module_fname, 'c.cc'],
                    include_dirs=['.'])

setup(name='PyBindGen-example',
    version="0.0",
    description='PyBindGen example',
    author='xxx',
    author_email='yyy@zz',
    ext_modules=[mymodule],
    )

我的 python 脚本使用扩展模块

import c

def my_callback(value):
    print("In Callback: " + str(value))

c.register_cb(my_callback)
c.set_num(10);
c.set_num(20);

最佳答案

我想通了。事后看来,这是显而易见的。我只需将所需的行放入对 wrapper.before_call.write_code() 的调用中,在我希望实际 C 行出现的位置。

关于python - 带回调的 PyBindGen,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55425473/

相关文章:

python - 使用 tensorflow ,如何平均多个批处理的参数梯度值并使用该平均值进行更新?

java - 如何使用正则表达式来匹配最后两个字符是前两个字符倒序的任何字符串

c++ - Oracle 中触发 SQL 查询的底层机制

c - 使用 Valgrind 调试我的程序

python - 如何使用 BeautifulSoup 查找元素的父标签?

python - 我有多个 flask 微服务彼此通信,如何配置docker?

c - 我们如何在C语言中将list(Python中的)函数实现为数组?

python-3.x - imgaug.augmenters.Affine 中的 'order' 参数到底是如何工作的?

python-3.x - 尝试旋转数据帧时出现类型错误 : No matching signature found,

python - 用于包装尝试的通用装饰器除了在 python 中?