2010-03-18 23 views
10

C işlevi myfunc, daha büyük bir veri yığınında çalışır. Sonuçlar bir geri çağırma işlevine parçalar döndürülür:Python nesnelerini ctypes geri arama işlevlerinde userdata olarak döndürme

int myfunc(const char *data, int (*callback)(char *result, void *userdata), void *userdata); 

ctypes kullanarak, Python kodundan myfunc aramaya ve sonuçlar bir Python geri arama işlevine iade edilen olması hiç önemli değil. Bu geri arama iyi çalışıyor.

myfunc = mylib.myfunc 
myfunc.restype = c_int 
myfuncFUNCTYPE = CFUNCTYPE(STRING, c_void_p) 
myfunc.argtypes = [POINTER(c_char), callbackFUNCTYPE, c_void_p] 

def mycb(result, userdata): 
    print result 
    return True 

input="A large chunk of data." 
myfunc(input, myfuncFUNCTYPE(mycb), 0) 

Fakat, geri arama işlevine userdata olarak bir Python nesnesini (diyelim bir liste) vermek üzere herhangi bir yolu var mı? Sonuç parçalarını uzakta saklamak için, ben mesela yapmak istiyorum:

def mycb(result, userdata): 
    userdata.append(result) 

userdata=[] 

Ama MyFunc çağrısına kullanılabilir böylece, nasıl bir c_void_p için Python kadro listesinde hiçbir fikrim yok .

Şu anki çözümüm, bağlantılı bir listeyi oldukça hantal olan bir klişe yapısı olarak uygulamaktır.

cevap

3

Bunu yapmak için Python C API kullanabilirdiniz ... belki de bir PyObject işaretçisi kullanabilirsiniz.

düzenlemek: op Açıklamalarda belirttiği gibi, orada zaten ctypes bir py_object tip hazır, bu yüzden çözüm geçmek c_void_p bunu döküm daha sonra ilk piton listesinden bir ctypes.py_object nesne oluşturmak için ve C işlevine bir argüman olarak (bu adımın void* olarak yazılan bir parametrenin herhangi bir işaretçiyi kabul etmesi gerektiği için gereksiz olabileceğini düşünüyorum ve sadece byref'u geçmek daha hızlı olacaktır). Geri aramada, ters adımlar yapılır (boşluk işaretçisinden py_object işaretçisine dökülür ve sonra içeriğin değeri alınır). Zaten hangi o öğeleri eklemek zorundadır listelemek bilmesi için

bir geçici çözüm ... Geri arama işlevi için bir kapatma kullanmak olabilir

myfunc = mylib.myfunc 
myfunc.restype = c_int 
myfuncFUNCTYPE = CFUNCTYPE(STRING) 
myfunc.argtypes = [POINTER(c_char), callbackFUNCTYPE] 


def mycb(result, userdata): 
    userdata.append(result) 

input="A large chunk of data." 
userdata = [] 
myfunc(input, myfuncFUNCTYPE(lambda x: mycb(x, userdata))) 
+0

Eh, ctypes hakkında güzel bir şey her şey olabilir olduğunu düz Python'da yapıldı. Yani Python C API bir geri adım gibi görünüyor. Yoksa bir şey mi özlüyorum? – flight

+0

Bu seçenek bir C-API PyObject yapısının bir ktypes proxy'si oluşturabilirdi, bu herhangi bir Python nesnesinin içsel gösterimi olmalıydı ve etrafından geçiyordu… – fortran

+0

Garip. Bir kapatma ile geçici çözümünüz Linux üzerinde iyi çalışıyor, ancak aynı program Windows'ta çöküyor. – flight