2015-12-10 2 views
2

Мне нужно вызвать функцию C из Python, используя ctypes и чтобы эта функция предоставляла один или несколько массивов обратно Python. Массивы всегда будут иметь простые типы, такие как long, bool, double.Вывод массива из Python ctypes?

Я бы очень хотел, чтобы массивы могли быть динамически разнесены. Я буду знать, что нужно перед каждым вызовом, но разные вызовы должны использовать разные размеры.

Предполагаю, что я должен выделить массивы на Python и позволить C-коду перезаписывать содержимое, так что Python может в конечном итоге де-выделить выделенную память.

Я управляю как кодом Python, так и кодом C.

У меня это сейчас, не работает:

C:

FOO_API long Foo(long* batch, long bufferSize) 
{ 
    for (size_t i = 0; i < bufferSize; i++) 
    { 
     batch[i] = i; 
    } 
    return 0; 
} 

Python:

print "start test" 
FooFunction = Bar.LoadedDll.Foo 
longPtrType = ctypes.POINTER(ctypes.c_long) 
FooFunction.argtypes = [longPtrType, ctypes.c_long] 
FooFunction.restype = ctypes.c_long 

arrayType = ctypes.c_long * 7 
pyArray = [1] * 7 
print pyArray 
errorCode = FooFunction(arrayType(*pyArray), 7) 
print pyArray 
print "test finished" 

Производит:

start test 
[1, 1, 1, 1, 1, 1, 1] 
[1, 1, 1, 1, 1, 1, 1] 
test finished 

должны производить:

start test 
[1, 1, 1, 1, 1, 1, 1] 
[0, 1, 2, 3, 4, 5, 6] 
test finished 

Почему это не работает? Или мне нужно сделать это по-другому?

+0

Возможно, попробуйте Cython + numpy, см. Здесь http://kbarbary.github.io/blog/cython-and-multiple-numpy-dtypes/ – mirosval

+0

@mirosval: Нет, спасибо. Решение достаточно сложно, как есть. – ThomasI

ответ

0

Массив C построен с использованием списка python; оба являются разными объектами. И код печатает список python, на который не влияет вызов Foo.

Вы должны построить массив C, передать его, а затем использовать его после вызова:

arrayType = ctypes.c_long * 7 
array = arrayType(*[1] * 7) 
print list(array) 
errorCode = FooFunction(array, len(array)) 
print list(array) 
+0

Спасибо. Я пришел к другому варианту, который я опубликовал, но я отмечаю ваш ответ как решение, так как вы получили его первым, и поскольку ваш ответ меняет мой исходный код меньше моего. Интересно, если по какой-то причине предпочтительнее другого? Вопросы эффективности. – ThomasI

+0

P.S. Я новичок в StackOverflow. Есть ли что-то, что я должен сделать, чтобы получать уведомления по электронной почте? – ThomasI

0

Благодаря falsetru за очень быстрый ответ. Я не заметил этого сразу, и, к тому времени, я пришел к этому, что тоже сработало. Интересно, предпочтительнее ли другое?

print "start test" 
FooFunction = GpGlobals.LoadedDll.Foo 
longArrayType = ctypes.c_long * (7) 
FooFunction.argtypes = [longArrayType, ctypes.c_long] 
FooFunction.restype = ctypes.c_long 

pyArray = longArrayType() 
for l in pyArray: 
    print l   
errorCode = FooFunction(pyArray, 7) 
for l in pyArray: 
    print l 
print "test finished" 

я первоначально не думаю, что это будет работать с динамически размеров массивов, но все, что я должен был сделать переопределять argtypes перед каждым вызовом.

+0

Вам было лучше использовать 'ctypes.POINTER (ctypes.c_long)' в 'argtypes', так как он принимает любой указатель' long * ', включая массивы' long' любого размера, поскольку они переданы как указатель. Что касается итерации результата вместо создания списка, это предпочтительнее, если вам действительно не нужно создавать список. Нет необходимости дублировать данные в двух объектах. – eryksun

Смежные вопросы