我有一个C api,我正在与python ctypes包接口.一切都很好,除了这个小小的花絮.
要将函数注册为某些通知的回调,我调用此函数:
void RegisterNotifyCallback( int loginId, int extraFlags, void *(*callbackFunc)(Notification *))
Run Code Online (Sandbox Code Playgroud)
所以在python我的代码看起来像:
CALLBACK = ctypes.CFUNCTYPE(None, ctypes.POINTER(Notification))
func = CALLBACK(myPythonCallback)
myLib.RegisterNofityCallback(45454, 0, func)
Run Code Online (Sandbox Code Playgroud)
如果myPythonCallback的值是FunctionType(即不是方法),它可以正常工作并使用正确的参数调用回调函数.如果它是一个MethodType,它仍会调用方法,但一旦方法完成,就会出现段错误.
编辑
澄清一下,当我说函数类型时,我的意思是将myPythonCallback定义为函数,
def myPythonCallback(Notification):
...do something with the Notification object i get passed in
Run Code Online (Sandbox Code Playgroud)
当我说它是一个MethodType时,我的意思是一个类方法:
class MyClass(object):
def myPythonCallback(self, Notification):
...do something with Notification
Run Code Online (Sandbox Code Playgroud)
它爆炸了第二种类型.
这周围有一个轻松的地方吗?或者有人可以向我解释为什么会发生这种情况?
非常感谢,Al.
编辑
用GDB进一步挖掘我的方法:
Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 1544567712 (LWP 5389)] 0x555ae962 in instancemethod_dealloc (im=0x558ed644) at Objects/classobject.c:2360 2360 Objects/classobject.c: No such file or directory.
in Objects/classobject.c (gdb) backtrace
#0 0x555ae962 in instancemethod_dealloc (im=0x558ed644) at Objects/classobject.c:2360
#1 0x555f6a61 in tupledealloc (op=0x5592010c) at Objects/tupleobject.c:220
#2 0x555aeed1 in instancemethod_call (func=0x558db8ec, arg=0x5592010c, kw=0x0) at Objects/classobject.c:2579
#3 0x5559aedb in PyObject_Call (func=0x558db8ec, arg=0x5592c0ec, kw=0x0) at Objects/abstract.c:2529
#4 0x5563d5af in PyEval_CallObjectWithKeywords (func=0x558db8ec, arg=0x5592c0ec, kw=0x0) at Python/ceval.c:3881
#5 0x5559ae6a in PyObject_CallObject (o=0x0, a=0x0) at Objects/abstract.c:2517
Run Code Online (Sandbox Code Playgroud)
传递给instancemethod_dealloc的值是:
(gdb) x 0x558ed644 0x558ed644: 0x00000000
Run Code Online (Sandbox Code Playgroud)
你认为这是可以解决的吗?
据我所知,你不能调用绑定方法,因为它缺少self参数.我使用闭包来解决这个问题,如下所示:
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())
Run Code Online (Sandbox Code Playgroud)
这可能是一个 ctypes 错误,涉及为方法与函数设置堆栈背后的魔力。
您是否尝试过通过 lambda 或函数使用包装器?
拉姆达:
func = CALLBACK(lambda x: myPythonCallback(x))
Run Code Online (Sandbox Code Playgroud)
功能:
def wrapper(x): myPythonCallback(x)
func = CALLBACK(wrapper)
Run Code Online (Sandbox Code Playgroud)
还有第三种方法使用闭包。如果您从类内部设置回调,则由于作用域,下面定义的方法应该继承“self”参数 - 使其表现得像类方法,尽管它是常规函数。
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)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3889 次 |
| 最近记录: |