Обтекание предварительно инициализированного указателя в классе cython

Я пытаюсь использовать библиотеку C, которая использует функцию обратного вызова (callback_function), чтобы предоставить указатель на структуру, которую я хотел бы обернуть (glp_tree).

Каков правильный способ инициализации экземпляра указателем, не созданным в __cinit__ ? Я не могу найти пример этого шаблона в документации на cython.

У меня есть рабочий код (см. Ниже), в котором указатель на целое и обратно, но я не уверен, что это хорошая практика / разум.

 cdef extern from "stdint.h": ctypedef unsigned long long uint64_t cdef extern from "glpk.h": ctypedef struct glp_tree: pass cdef void callback_func(glp_tree* tree, void *info): treeobj = Tree(<uint64_t>tree) // cast to an integer... cdef class Tree: cdef glp_tree* ptr def __init__(self, uint64_t ptr): self.ptr = <glp_tree*>ptr // ... and back to a pointer 

Передача объекта glp_tree напрямую работает (хотя это не то, что я хочу сделать), но попытка передать указатель приводит к ошибке компилятора:

 Cannot convert 'glp_tree *' to Python object 

Вместо использования __init__ / __cinit__ (который всегда ожидает объектов Python в качестве аргументов), вы можете использовать пользовательский @staticmethod cdef для создания экземпляров:

 cdef class Tree: cdef glp_tree* ptr def __init__(self, *args): raise TypeError('Cannot create instance from Python') @staticmethod cdef Tree create(glp_tree* ptr): obj = <Tree>Tree.__new__(Tree) # create instance without calling __init__ obj.ptr = ptr return obj 

Выделение указателя на целое является опцией, но тогда правильный тип для использования – uintptr_t , а не uint64_t (он самодокументирован и всегда имеет правильную ширину для платформы).

Проблема в том, что построение Tree – это операция Python, как вы можете ясно видеть на cython -a . Вход в конструктор должен быть преобразован в структуры данных Python, а указатели не имеют очевидного преобразования.

Это будет работать

 cdef class Tree: cdef glp_tree* ptr def __init__(self, long ptr): self.ptr = <glp_tree*>PyLong_AsVoidPtr(ptr)