I'm trying to use a C library which uses a callback function (callback_function) to provide a pointer to a struct I'd like to wrap (glp_tree).
What is the correct way to initialize an instance with a pointer not created in __cinit__
? I can't find an example of this pattern in the cython documentation.
I have some working code (see below), which casts the pointer to an integer and back, but I'm not sure this is good practice / sane.
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
Passing the glp_tree object directly seems to work (although it's not what I want to do), but trying to pass the pointer results in a compiler error:
Cannot convert 'glp_tree *' to Python object
Instead of using __init__
/__cinit__
(which always expects Python objects as arguments), you can use a custom @staticmethod cdef
to create instances:
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
Casting a pointer to an integer is an option, but then the correct type to use is uintptr_t
, not uint64_t
(it's self-documenting and always has the right width for the platform).
The problem is that constructing a Tree
is a Python operation, as you can clearly see in the cython -a
output. The input to the constructor has to be converted to Python data structures, and pointers have no obvious conversion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With