Cython回调对函数正常,但对绑定方法不正常

8 投票
1 回答
1533 浏览
提问于 2025-04-17 01:37

我正在实现一个基于Cython的接口,用来和一个C++库进行交互。我做了一个回调系统,它在使用普通函数时工作正常,但在传入绑定方法时却出现了奇怪的问题。以下是我的Cython代码的一部分:

cdef extern from "VolumeHapticTool.h":
    cdef cppclass HDButtonEvent:
        bool isPressed()
        unsigned int getButtonId()
        Vec3[float] getPosition()

    ctypedef void (*HDButtonCallback)(HDButtonEvent, void *)

cdef extern from "Scene.h":
    cdef cppclass Scene:
        Scene()
        void setDrillButtonCallback( HDButtonCallback, void*)

cdef void pyHDButtonCallback(HDButtonEvent e, void *user_data):
    print <object>user_data
    (<object>user_data)( (e.isPressed(), e.getButtonId(), topy_vec3f(e.getPosition())) )

cdef class pyScene:
    cdef Scene * m_scene
    def __init__(self):
        self.m_scene = new Scene()

    def __del__(self):
        del self.m_scene

    def setDrillButtonCallback(self, func):
        print func
        self.m_scene.setDrillButtonCallback(pyHDButtonCallback, <void*>func)

这是我尝试调用它的方式:

class RenderCanvas(GLCanvas):
    def __init__(self, parent):
        self.scene = cybraincase.pyScene()
        self.scene.setDrillButtonCallback(self.OnDrillButtonPress)

    def OnDrillButtonPress(self, event):
        print event 

当这段代码第一次运行时,打印出来的是: <bound method RenderCanvas.OnDrillButtonPress of <UI.RenderCanvas; proxy of <Swig Object of type 'wxGLCanvas *' at 0x42b70a8> >>

看起来没问题。问题出现在回调被触发时,打印出来的是: <bound method Shell.readline of <wx.py.shell.Shell; proxy of <Swig Object of type 'wxStyledTextCtrl *' at 0x3a12348> >>

这时调用的是一个完全不同的绑定方法。不过,当我把OnDrillButtonPress改成静态方法时, <function OnDrillButtonPress at 0x042FC570> 在初始化和触发调用时都会打印出来。

难道保存绑定方法为void*时会有不兼容的问题吗?

1 个回答

3

感谢Stefan Behnel和Mark Florisson在cython讨论组的评论,我发现问题是我绑定的方法引用失去了作用域,结果被垃圾回收了。

解决办法是这样做:

cdef class pyScene:
    cdef Scene * m_scene
    cdef object drill_button_func

    def setDrillButtonCallback(self, func):
        self.m_scene.setDrillButtonCallback(pyHDButtonCallback, <void*>func)
        self.drill_button_func = func

通过在类中保留对这个绑定方法的引用,它就不会被清理,直到不再使用为止。

撰写回答