2011-08-31 11 views
11

मेरे पास एक सी एपीआई है कि मैं पाइथन ctypes पैकेज के साथ इंटरफेसिंग कर रहा हूं। इस छोटी सी चीज को छोड़कर, सब ठीक काम करता है।पायथन के प्रकार के साथ कॉलबैक के रूप में काम करने के तरीकों को कैसे प्राप्त किया जा सकता है?

कुछ सूचनाएं लिए कॉलबैक के रूप में कार्य करता रजिस्टर करने के लिए, मैं फोन इस समारोह:

void RegisterNotifyCallback(int loginId, int extraFlags, void *(*callbackFunc)(Notification *)) 

तो अजगर में मेरी कोड लगता है: myPythonCallback का मूल्य

CALLBACK = ctypes.CFUNCTYPE(None, ctypes.POINTER(Notification)) 
func = CALLBACK(myPythonCallback) 
myLib.RegisterNofityCallback(45454, 0, func) 

तो एक FunctionType है (यानी एक विधि नहीं), यह ठीक काम करता है और कॉलबैक फ़ंक्शन को सही पैरामीटर के साथ कॉल करता है। यदि यह एक विधि टाइप है, तो यह विधि को अभी भी कॉल करता है लेकिन विधि समाप्त होने के बाद फिर सेगफॉल्ट के साथ उड़ाता है।

संपादित

स्पष्ट करने के लिए, जब मैं कहना समारोह प्रकार मेरा मतलब है कि myPythonCallback एक समारोह के रूप में परिभाषित किया गया,

def myPythonCallback(Notification): 
    ...do something with the Notification object i get passed in 

जब मैं कहना है कि यह एक MethodType है, मैं एक वर्ग विधि मतलब है:

class MyClass(object): 
    def myPythonCallback(self, Notification): 
     ...do something with Notification 

यह दूसरे प्रकार पर उड़ाता है।

क्या इसके आसपास कोई आसान दूर है? या क्या कोई मुझे यह बता सकता है कि यह क्यों हो रहा है?

बहुत धन्यवाद, अल।

संपादित

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 

और instancemethod_dealloc में पारित मूल्य है:

(gdb) x 0x558ed644 0x558ed644:  0x00000000 

आप मानना ​​है कि यह क्षम्य है?

+0

आप सी एपीआई में cdecl या stdcall का उपयोग कर रहे हैं? मुझे नहीं पता कि फ़ंक्शन प्रकार और विधि प्रकार के बीच भेद से आपका क्या मतलब है। कृपया आप फॉर्म के कोड नमूने के साथ संभवतः और अधिक समझा सकते हैं जो काम करता है और वह फॉर्म जो नहीं करता है। वैसे, मैंने सफलतापूर्वक ctypes के साथ कॉलबैक बनाया है, इसलिए मुझे यकीन है कि यह संभव है। –

+0

कृपया संपादन देखें। – AlMcLean

उत्तर

3

यह विधियों बनाम कार्यों के लिए ढेर की स्थापना के पीछे जादू से निपटने वाला एक प्रकार का बग हो सकता है।

क्या आपने लैम्ब्डा या फ़ंक्शन के माध्यम से एक रैपर का उपयोग करने का प्रयास किया है?

लैम्ब्डा:

func = CALLBACK(lambda x: myPythonCallback(x)) 

फंक्शन:

def wrapper(x): myPythonCallback(x) 
func = CALLBACK(wrapper) 

एक तिहाई विधि बंद का उपयोग कर नहीं है। यदि आप कक्षा के अंदर से कॉलबैक स्थापित कर रहे हैं, तो नीचे परिभाषित विधि को दायरे के कारण "स्वयं" तर्क प्राप्त करना चाहिए - यह नियमित कार्य होने के बावजूद कक्षा विधि की तरह कार्य करता है।

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) 
+0

हम्म मैं इसे आज़मा दूंगा, कोड काम पर है, मैं आपके फिक्स के साथ घर पर कोशिश और दोहराना चाहूंगा। – AlMcLean

+0

एक और बात - क्या आपकी विधि और कार्य में एक ही कार्यवाही है? एक बार – lunixbochs

+0

वापस लौटने के बाद फ़ंक्शन के दौरान डेटा में हेरफेर करना संभव है, हाँ, यह वही बात है। मैं एक संरचना में हेरफेर कर रहा हूं, इसलिए मेरे पास सेगफाल्ट का उचित हिस्सा रहा है, जबकि एक को चिढ़ाते हुए मुझे पता है कि क्या देखना है। कॉलबैक फ़ंक्शन को कॉल ' फ़ाइल " – AlMcLean

7

आप जहां तक ​​जानते हैं, एक बाध्य विधि को कॉल नहीं कर सकते क्योंकि यह स्वयं पैरामीटर गायब है।मैं इस समस्या को बंद करने का उपयोग कर हल कर देते हैं:

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()) 
+0

ठीक है, मैं इसके पीछे तर्क देखता हूं। मैं इसे लेता हूं कि अगर मैं कॉलबैक के रूप में किसी अन्य वर्ग से बाध्य विधि में गुजरना चाहता हूं तो मुझे बंद करने की चाल की आवश्यकता है? तो क्या यह एक बग है या जिस तरह से इसे डिजाइन किया गया है? – AlMcLean

+1

self.getCallbackFunc() को एक आंतरिक चर (उदा। Self.callback) में असाइन करने के लिए सावधान रहें, अन्यथा func() कचरा एकत्रित किया जाएगा और कार्यक्रम SIGSEGV के साथ समाप्त हो जाएगा। –

संबंधित मुद्दे

 संबंधित मुद्दे