Cython - преобразование указателей на массивы в объекты Python - PullRequest
10 голосов
/ 11 марта 2011

Хорошо, я так близок к тому, чтобы закончить это, что могу попробовать.В течение последних нескольких недель я пытался создать расширение Python для взаимодействия с библиотекой, написанной на C ++ через Cython.С небольшой помощью парней здесь и пары друзей мне удалось получить то, что кажется 98% пути туда.Единственное, что осталось, так это: я не могу на всю жизнь понять, как превратить указатель на массив беззнаковых шорт в объект python (предпочтительно список).

Немного фона, япытаясь взаимодействовать с частью библиотеки, которая устанавливает функцию обратного вызова, что я успешно сделал с этим:

global callbackfunc

ctypedef unsigned short const_ushort "const uint16_t"

ctypedef void (*Function1)(const_ushort *data, unsigned width, unsigned height)

cdef extern from "lib.hpp":
    void SetCallback(Function1)

cdef void cSetCallback(Function1 function):
    SetCallback(function)

cdef void callcallback(const_ushort *data, unsigned width, unsigned height):
    global callbackfunc
    callbackfunc(data,width,height)

cSetCallback(callcallback)

def PySetCallback(callbackFunc):
    global callbackfunc
    callbackfunc = callbackFunc

Проблема возникает в функции "callcallback", где я получаю сообщение об ошибке: "Не могупреобразовать const_ushort * в объект Python ".Моей первой попыткой было создать новый список Python и выполнить цикл, чтобы получить каждый элемент массива в список Python, например:

datalist = []
for i in range(width*height):
    datalist += data[i]

Что, к сожалению, связывает меня с скомпилированным Cythonкод, пытающийся определить тип как «const const unsigned short», что, очевидно, является проблемой.

Затем я попытался это сделать:

datalist = []
for i in data:
    datalist += i

Что дает мне «Итерация массива C требует известныхконечный индекс ".Обратите внимание, что я очень мало знаю C / C ++, поэтому большая часть этого не имеет для меня особого смысла.

Итак, в любом случае, есть ли эффективный способ перевода указателя, подобного этому, в объект python (предпочтительнобыстрее, чем циклически проходить по массиву, так как обычно он содержит около 57344 элементов, и это довольно чувствительно ко времении функция C ++ в библиотеке, которая вызывает это, отправляет указатель на массив «const uint_16», именно поэтому я определил const_ushort таким образом, потому что в противном случае типы не объединяются.Я никак не могу изменить библиотеку.

Edit2 : Похоже, я ее получил.То, что мне пришлось сделать, это явное приведение массива в виде массива беззнаковых шорт, а не массива константных беззнаковых шорт, чтобы я мог индексировать их с помощью не константы.Чтобы добиться этого, я создал другую функцию C ++, подобную этой (кто-то другой написал ее для меня, я едва знаю C ++):

unsigned short *convert_short(const unsigned short *test){ return const_cast<unsigned short *>(test); }

, и это позволило мне создать " getindex "функция в моем классе и вернуть правильные значения на основе функции.Так что да, Python, похоже, правильно читает массивы и так далее, поэтому этот случай кажется закрытым.Большое спасибо.

Ответы [ 2 ]

4 голосов
/ 11 марта 2011
ctypedef unsigned short const_ushort "const uint16_t"

заставляет const появляться в коде C, так что вы получаете typedef unsigned short const uint16_t, в котором const не имеет смысла.(Он также переопределяет стандартный тип uint16_t, чего не должно быть.)

Вы можете добиться большего успеха с

ctypedef unsigned short *ushort_p "ushort_p"

По какой-то причине Cython, похоже, не распознает Cconst ключевое слово.Возможно, вам придется использовать оболочку вокруг ваших обратных вызовов для решения проблемы const.

Если вы хотите, чтобы указатель был преобразован в объект Python, оберните его в cdef class.Убедитесь, что класс записывает высоту и ширину, поскольку они не записаны в массиве C.

1 голос
/ 11 марта 2011

Это не совсем то, что вы спрашиваете, но если вы хотите работать с массивом шорт без знака в Cython, а затем сделать свой ответ доступным на стороне Python, вы можете создать Numpy ndarray на Pythonсторона и передать его в Cython, где он примерно такой же, как многомерный массив.Таким образом, вы получаете как управление памятью в Python, так и удобный синтаксис индексации, а также скорость работы с реальным массивом в Cython.

Вот пример из моих решений Project Euler.

...