Обёртывание перечисления typedefed в cython - PullRequest
0 голосов
/ 05 января 2019

Я хотел бы обернуть следующий код в Cython:

enum Status {GOOD, BAD};

typedef enum Status STATUS;
// note that the typedef means people dont
// have to write `enum Status` everywhere

// just returns `GOOD`
STATUS hello();

Я написал следующий код Cython в c_library.pxd:

cdef extern from "library.h":

  cpdef enum Status:
    GOOD,
    BAD

  ctypedef Status STATUS

  cpdef STATUS hello()

Модуль c_library теперь содержит c_library.GOOD, c_library.BAD, и c_library.Status, который ведет себя как enum . Тем не менее возвращаемое значение вызова функции hello возвращает обычное значение int:

>>> c_library.hello()
0
>>> type(c_library.hello())
<class 'int'>

Я бы хотел, чтобы результат был также помещен в перечисление того же типа. Я могу изменить файл Cython, но не базовый C-код. Это возможно?

1 Ответ

0 голосов
/ 05 января 2019

Это похоже на сбой (незначительную ошибку?) В Cython, который решает использовать __Pyx_PyInt_From_enum__ по некоторым причинам при переносе cdef -функции в def функцию.

В качестве быстрого обходного пути я могу предложить явно создать Status -enum:

%%cython
cdef extern from *:
    """
    typedef enum Status {GOOD, BAD} Status;

    // just returns `GOOD`
    Status hello() {return GOOD;}
    """
    cpdef enum Status:
        GOOD,
        BAD

    Status c_hello "hello"()

def hello():
    return Status(c_hello())

А сейчас:

>>> type(hello())
<enum 'Status'>

Вещи, возможно, стоит отметить:

  • дословный C-код используется, чтобы сделать пример автономным.
  • Использование typedef enum X {...} X; для извлечения имени типа enum из пространства имен enum в пространство имен обычных переменных является обычной практикой (но, очевидно, это вопрос вкуса, поэтому, если вы предпочитаете STATUS - это до вы). См. Формулировку в стандарте C11 для разных пространств имен здесь или отличный ответ (даже если речь идет о struct).
  • cname -трюк (т. Е. Status c_hello "hello"()) используется, чтобы иметь возможность добавить уровень косвенности и сохранить неизменным открытый интерфейс модуля (т. Е. cpdef hello()).
  • Однако, при использовании hello в качестве cdef -функции, я бы, вероятно, использовал c_hello, чтобы избежать накладных расходов на создание перечисления - поэтому hello() определяется как def -функция, поэтому нет путаницы.
...