问题
I have structure declarations in my code:
cdef extern from "uuid/uuid.h":
ctypedef unsigned char uuid_t[16]
cdef extern from "fr_common.h":
ctypedef uuid_t fr_id_t
ctypedef struct fr_event_t:
fr_id_t id
size_t action
fr_id_t object_id
long long ts
Here I have cython class where I need to pass fr_id_t id
value from fr_event_t
structure.
cdef class Event:
cdef:
bytes _id
int _action
bytes object_id
int _ts
def __cinit__(self, fr_id_t id, int action, fr_id_t object_id, int ts):
self._id = id
self._action = action
self._object_id = object_id
self._ts = ts
@staticmethod
cdef Event from_c(fr_event_t fr_event):
return Event(
fr_id_t=fr_event.id,
action=fr_event.action,
object_id=fr_event.object_id,
ts=fr_event.ts,
How I can represent fr_id_t
type passing it in the function somehow else? Its representation is unsigned char uuid_t[16]
that stores bytes. Passing fr_id_t
is not working and cython compiler gives me assertion error while compiling my .pyx file into .so.
AssertionError: (<FileSourceDescriptor:/home/dmitriyravdel/teyefr/teye-fr/python/teyefr/_teyefr.pyx>, 356, 24): (__pyx_v_id == ((unsigned char *)NULL)) && PyErr_Occurred()
回答1:
The error message is a bug in Cython an makes it pretty hard to diagnose. However, what you're trying to do doesn't make a lot of sense to me.
__init__ and __cinit__ are fundamentally Python methods and their arguments must be Python objects
All constructor arguments will be passed as Python objects. This implies that non-convertible C types such as pointers or C++ objects cannot be passed into the constructor from Cython code. If this is needed, use a factory function instead that handles the object initialisation. It often helps to directly call
__new__()
in this function to bypass the call to the__init__()
constructor.
What will happen (if your code worked) is that first fr_event.id
will be converted to a Python object to be passed to __cinit__
then it'll be converted back to a fr_id_t
, then it'll be converted to a bytes
where you store it. This is not what you want! It looks like one of these conversions has confused Cython.
What you actually want to do is to create a genuinely empty Event
in from_c
:
@staticmethod
cdef from_c(fr_event_t event):
cdef Event e = Event.__new__() # This only works if __cinit__ is removed or takes no arguments
e._id = event.id
# etc
return e
You also cannot have fr_id_t
arguments to __cinit__
since these are what triggers the issue. I'd suggest that it isn't meaningful to construct Event
objects from Python (only Cython) so that you probably shouldn't have a __cinit__
at all. Another alternative would be to have a __cinit__
that takes the Python equivalent types bytes
and int
:
cdef class Event:
cdef bytes _id
def __cinit__(self, bytes id):
self._id = id
@staticmethod
cdef from_c(fr_event_t event):
return Event(event.id)
(I've cut this example down further for the sake of simplicity)
来源:https://stackoverflow.com/questions/63036383/cython-unsigned-char-uuid-t16-representaion