【问题标题】:Pass a callback function from python to c using cython使用 cython 将回调函数从 python 传递到 c
【发布时间】:2013-07-25 23:09:44
【问题描述】:

首先我想说的是,我没有修改甚至查看 c 源代码的选项,因此任何涉及修改 c 文件的操作都无济于事。

在 VP.h 中:

typedef enum VPEvent { 
  ...
  EVENT_OBJECT_CLICK,
  ...
}
...
typedef void *VPInstance;
typedef void(*VPEventHandler)(VPInstance);
...
VPSDK_API VPInstance vp_create(void);
...
VPSDK_API int vp_event_set(VPInstance instance, VPEvent eventname, VPEventHandler event);
...

在 VP.pyx 中:

cdef extern from "VP.h":
  ...
  cdef enum VPEvent:
    ...
    VP_EVENT_OBJECT_CLICK,
    ...

  ...
  ctypedef void *VPInstance
  ctypedef void(*VPEventHandler)(VPInstance)
  ...
  VPInstance vp_create()
  ...
  int vp_event_set(VPInstance instance, VPEvent eventname, VPEventHandler event)
  ...

...
EVENT_OBJECT_CLICK = VP_EVENT_OBJECT_CLICK
...

cdef class create:
  cdef VPInstance instance

  def __init__(self):
    self.instance = vp_create()
  ...
  def event_set(self, eventname, event):
    return vp_event_set(self.instance, eventname, event)

我想在 Python 中拥有什么:

import VP
...
def click(bot):
  bot.say("Someone clicked something!")
...
bot = VP.create()
bot.event_set(VP.EVENT_OBJECT_CLICK, click)

这就是你在 c 中的做法:

#include <VP.h>

void click(VPInstance instance) {
  vp_say(instance, "Someone clicked something!");
}

int main(int argc, char ** argv) {
  ...
  VPInstance instance;
  instance = vp_create();
  ...
  vp_event_set(instance, VP_EVENT_OBJECT_CLICK, click)
}

但是问题是在编译 VP.pyx 时我得到了

无法将 Python 对象转换为“VPEventHandler”

同样,默认情况下,回调被赋予一个 VPInstance 指针,但我想将此值抽象到一个类中。

【问题讨论】:

    标签: python c callback cython


    【解决方案1】:

    你可能已经猜到了,通话中的问题

    bot.event_set(VP.EVENT_OBJECT_CLICK, click)
    

    确实,第三个参数click 是一个Python 函数对象,您将它传递给event_setvp_event_set。唉,vp_event_set 期待一个 VPEventHandler,它是一个 void(*VPEventHandler)(VPInstance);

    类型的 C 函数指针

    我想我会构建一个与VPInstance 相关联的字典(void * 指针转换为整数)是一些PyEvent 类的实例,它应该包含自己的函数点击。使用它可以确保您需要一个 C 函数作为回调。

    foo.pxd:

    cdef class PyEvent(object):
         cdef VPInstance instance
         cdef object py_callback
    

    foo.pyx: 事件 = dict()

    cdef void EventCallBack(VPInstance instance):
         PyEvent ev = <PyEvent> dict[events[<size_t> self.instance]
         ev.py_callback(ev)
    
    cdef class PyEvent(object):
         def __init__(self, click):
             self.instance = vp_create()
             self.py_callback = click
    
         def event_set(self, eventname):
             global events
             events[<size_t> self.instance] = self
             return vp_event_set(self.instance, eventname, EventCallBack)
    

    我没有机会对此进行测试,所以我希望它或多或少有效。此外,我建议您在 cython-users@googlegroups.com 上提问,因为他们通常比我更有帮助且更专业。

    【讨论】:

    • 谢谢!这是我见过的唯一一个使用带有 python 对象的指针的 Cython 示例。即转换为 .
    【解决方案2】:

    我最终通过采用与 hivert 建议类似的方法解决了这个问题,但是我决定改用 swig,因为它是专门为语言绑定而构建的。

    这是我设置的精简版

    int swig_event_set(VPInstance instance, VPEvent eventname, PyObject * event);
    
    %{
    static PyObject * py_events[VP_HIGHEST_EVENT];
    static void PythonEvent(VPInstance instance, int eventname) {
      PyObject * func, * arglist;
      PyObject * result;
    
      func = py_events[eventname];
      arglist = Py_BuildValue("(O)", SWIG_NewPointerObj(SWIG_as_voidptr(instance), SWIGTYPE_p_void, 0));
      result = PyEval_CallObject(func, arglist);
      Py_DECREF(arglist);
      Py_XDECREF(result);
    }
    
    static void vp_event_object_click(VPInstance instance) {
      PythonEvent(instance, VP_EVENT_OBJECT_CLICK);
    }
    
    int swig_event_set(VPInstance instance, VPEvent eventname, PyObject * event) {
      Py_XDECREF(py_events[eventname]);  /* Dispose of previous event callback */
      Py_XINCREF(event);                 /* Add a reference to new event callback */
      py_events[eventname] = event;      /* Remember new event callback */
    
      switch(eventname) {
        case VP_EVENT_OBJECT_CLICK:
          return vp_event_set(instance, eventname, vp_event_object_click);
          break;
        case VP_HIGHEST_EVENT:
          break;
      }
    
      return 1;
    }
    %}
    

    【讨论】:

      猜你喜欢
      • 2012-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-10
      • 2020-09-14
      相关资源
      最近更新 更多