I have an C api that i\'m interfacing with the python ctypes package. Everything works well, except this little tidbit.
To register functions as callbacks to some n
This may be a ctypes bug dealing with the magic behind setting up the stack for methods vs functions.
Have you tried using a wrapper via lambda or function?
Lambda:
func = CALLBACK(lambda x: myPythonCallback(x))
Function:
def wrapper(x): myPythonCallback(x)
func = CALLBACK(wrapper)
There's a third method using closures. If you're setting up the callback from inside the class, the method defined below should inherit the "self" argument due to scope - making it act like a class method despite being a regular function.
class Foo:
def __init__(self):
def myPythonCallback(Notification):
print self # it's there!
pass # do something with notification
func = CALLBACK(myPythonCallback)
myLib.RegisterNofityCallback(45454, 0, func)
You can't, so far as I know, call a bound method because it is missing the self parameter. I solve this problem using a closure, like this:
CALLBACK = ctypes.CFUNCTYPE(None, ctypes.POINTER(Notification))
class MyClass(object):
def getCallbackFunc(self):
def func(Notification):
self.doSomething(Notification)
return CALLBACK(func)
def doRegister(self):
myLib.RegisterNofityCallback(45454, 0, self.getCallbackFunc())
Its been said but the segfault is probably caused by the garbage collection of the method, you have to store the reference. I solved both the missing self parameters and the garbage collection problem like this.
CALLBACK = ctypes.CFUNCTYPE(None, ctypes.POINTER(Notification))
class MyClass(object):
def myPythonCallback(self, Notification):
...do something with Notification
def __init__(self):
self.myPythonCallback = CALLBACK(self.myPythonCallback)
myLib.RegisterNofityCallback(45454, 0, self.myPythonCallback)
Every new instance of the class create the bound method (self.myPythonCallback), so each registered callback is specific to the class instance. We've held the reference to the callback in the class so it wont get garbage collected. The CFUNCTIONTYPE callback is executed as per normal same as if it were a global function <function_CFUNCTYPE>
, and its inner callback is the bound method <bound method myPythoncCallback of MyClass 0xfffabca0>
. Bound methods execute with self.
Note: although it looks a lot like you could just use @decorator syntax, that won't work. Decorators on methods decorate the original method and then bind to the class, so the effect is self.myPythonCallback would be a <bound CFUNCTYPE on MyClass>
calling a plain method <function myPythonCallback>
The closeure solution provided by @David-Heffernan was my inspiration,