Ошибка компиляции Cython для бесплатной функции (невозможно преобразовать аргумент объекта Python в тип FooBar *)

Я использую Cython (0.15.2) для создания расширения для Python (2.6.5). Я создал файл pxd и файл pyx. Вот содержимое моего файла pyx:

cimport capifuncs

cdef class myArray:
    cdef capifuncs.myArray *_my_array
    def __cinit__(self, size):
        self._my_array = capifuncs.array_new(size)
        if (self._my_array is NULL):
            raise MemoryError()

    def __dealloc__(self):
        if self._my_array is not NULL:
            capifuncs.array_free(self._my_array)

    def __bool__(self):
        return not capifuncs.IsEmpty(self._my_array)


    ##############################
    #        Array methods       #
    ##############################

    cpdef getItem(self, unsigned int pos):
        if capifuncs.IsEmpty(self._my_array):
            raise IndexError("Array is empty")
        #if ():
        #    raise IndexError("Array bounds exceeded")

        return capifuncs.array_get_item(self._my_array, pos)


    cpdef setItem(self, unsigned int pos, double val):
        if capifuncs.IsEmpty(self._my_array):
            raise IndexError("Array is empty")
        #if ():
        #    raise IndexError("Array bounds exceeded")

        capifuncs.array_set_item(self._my_array, pos, val)




# Free functions
cpdef long someCAPIFuncCall(capifuncs.FooBar *fb, capifuncs.myArray *arr, long start, long stop):
    return capifuncs.doSomethingInteresting(fb, arr, start, stop)

Если я закомментирую оператор определения свободной функции (т.е. не являющейся членом), код компилируется правильно и создается расширение. Однако, если я раскомментирую его и попытаюсь скомпилировать файл, я получу следующее сообщение об ошибке:

cafuncs.pyx: 64: 23: Невозможно преобразовать аргумент объекта Python в тип 'FooBar *'

В чем причина этого и как это исправить?


person Homunculus Reticulli    schedule 07.11.2011    source источник


Ответы (1)


Функция, определенная как cpdef, может быть вызвана как из Python, так и из C.

Если аргументы объявлены как типы данных C, Cython попытается автоматически преобразовать объекты, переданные в функцию, когда она вызывается из Python. Но такие преобразования возможны только для числовых и строковых типов - все другие типы приведут к ошибке времени компиляции.

Вы хотели предоставить эту функцию Python? Если нет, определите его с помощью cdef.

В противном случае вам нужно будет создать оболочки для типов C, которые вы хотите передавать в Python и из Python. См. Несколько примеров того, как это сделать, в Руководствах по Cython.

person ekhumoro    schedule 07.11.2011
comment
да, я хочу иметь возможность вызывать функцию C из Python - причина создания расширения заключается в том, чтобы иметь возможность использовать типы данных и функции в библиотеке C из Python - поэтому мне действительно нужно иметь возможность вызывать функция C из Python и передать ей типы данных C (из Python) - person Homunculus Reticulli; 07.11.2011
comment
Incodentally, если я использую cdef вместо cpdef, код компилируется, но я получаю следующее предупреждающее сообщение: warning: ‘__pyx_f_6clib_doSomethingInteresting’ определено, но не используется. К сожалению, когда я пытаюсь использовать функцию из python, я получаю сообщение об ошибке AttributeError: объект 'module' не имеет атрибута 'doSomethingInteresting' - person Homunculus Reticulli; 07.11.2011
comment
@HomunculusReticulli. См. Мой обновленный ответ. По сути, вам нужно создавать оболочки для ваших типов C. - person ekhumoro; 07.11.2011
comment
Я уже создал оболочки для моих типов C - при условии, что я не показывал класс cdef для FooBar во фрагменте в моем вопросе (для краткости). - person Homunculus Reticulli; 08.11.2011
comment
Проблема с примерами в ссылке заключается в том, что они показывают только, как реализовать методы объекта - они не показывают, как вызывать бесплатные (не являющиеся членами) функции, которые принимают типы данных C в качестве аргументов. - person Homunculus Reticulli; 08.11.2011
comment
@HomunculusReticulli. Вы пробовали someCAPIFuncCall(capifuncs.FooBar fb, capifuncs.myArray arr, ...? - person ekhumoro; 08.11.2011
comment
Да, исходный код был таким, но у меня были ошибки компиляции (я не могу вспомнить сообщение). Кстати, пока я ждал ответа на этот вопрос, я решил переключиться на SWIG. С тех пор я успешно построил модуль (используя SWIG) и сейчас тестирую его. - person Homunculus Reticulli; 08.11.2011