Cython 回调适用于函数,但不适用于绑定方法

发布于 2024-12-03 06:47:34 字数 1823 浏览 0 评论 0 原文

我正在实现一个基于 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 

最初运行此代码时,将打印以下内容: < >>

看来是对的。问题是当回调被触发时,会打印以下内容: < >>

正在调用完全不同的绑定方法。但是,当我将 OnDrillButtonPress 设为静态方法时, <0x042FC570 处的 OnDrillButtonPress 函数> 在初始化和触发调用时都会打印。

将绑定方法保存为 void* 是否不兼容?

I am implementing a cython-based interface to a C++ library. I implemented a callback system that works with normal functions but fails strangely when passing in bound methods. Here is a portion of my cython code:

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)

And here is how I'm trying to call it:

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

    def OnDrillButtonPress(self, event):
        print event 

When this code is run initially, this is printed:
<bound method RenderCanvas.OnDrillButtonPress of <UI.RenderCanvas; proxy of <Swig Object of type 'wxGLCanvas *' at 0x42b70a8> >>

That seems right. The problem is when the callback is triggered, this is printed:
<bound method Shell.readline of <wx.py.shell.Shell; proxy of <Swig Object of type 'wxStyledTextCtrl *' at 0x3a12348> >>

A totally different bound method is being called. However, when I make OnDrillButtonPress a static method,
<function OnDrillButtonPress at 0x042FC570>
is printed both on initialization and triggering calls.

Is there an incompatibility with saving bound methods as void*?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

神妖 2024-12-10 06:47:34

感谢 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

通过在类中保留对绑定方法的引用,直到停止使用它才会被清理。

Thanks to comments by Stefan Behnel and Mark Florisson on the cython discussion group, the problem is that the reference to my bound method was going out of scope and getting garbage collected.

The solution was to do this:

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

By keeping a reference to the bound method in the class, it doesn't get cleaned up until it stops being used.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文