Commit f267baea authored by Pan's avatar Pan

fixup! Added documentation on extension class instantiation from existing pointer

parent f0552fe2
...@@ -554,43 +554,67 @@ contructors, this necessitates the use of factory functions. For example, :: ...@@ -554,43 +554,67 @@ contructors, this necessitates the use of factory functions. For example, ::
cdef class WrapperClass: cdef class WrapperClass:
"""A wrapper class for a C/C++ data structure""" """A wrapper class for a C/C++ data structure"""
cdef my_c_struct *_ptr cdef my_c_struct *_ptr
cdef bint ptr_owner
def __cinit__(self): def __cinit__(self):
# On cinit, do not create new structure but set pointer to NULL # On cinit, do not create new structure but set pointer to NULL
self._ptr = NULL self._ptr = NULL
self.ptr_owner = True
def __dealloc__(self): def __dealloc__(self):
# De-allocate if we have a non-null pointer # De-allocate if not null and flag is set
if self._ptr is not NULL: if self._ptr is not NULL and self.ptr_owner is True:
free(self._ptr) free(self._ptr)
self._ptr = NULL
# Extension class properties
@property
def a(self):
return self._ptr.a if self._ptr is not NULL else None
cdef WrapperClass PyWrapperClass(my_c_struct *_ptr): @property
"""Factory function to create WrapperClass objects from def b(self):
given my_c_struct pointer""" return self._ptr.b if self._ptr is not NULL else None
# Call to __new__ bypasses __init__ constructor
cdef WrapperClass wrapper = WrapperClass.__new__(WrapperClass)
wrapper._ptr = _ptr
return wrapper
@staticmethod
cdef WrapperClass from_ptr(my_c_struct *_ptr):
"""Factory function to create WrapperClass objects from
given my_c_struct pointer"""
# Call to __new__ bypasses __init__ constructor
cdef WrapperClass wrapper = WrapperClass.__new__(WrapperClass)
wrapper._ptr = _ptr
return wrapper
cdef WrapperClass PyNewWrapperClass(): @staticmethod
"""Factory function to create WrapperClass objects with cdef WrapperClass new_struct():
newly allocated my_c_struct""" """Factory function to create WrapperClass objects with
cdef my_c_struct *_ptr = <my_c_struct *>malloc(sizeof(my_c_struct)) newly allocated my_c_struct"""
return PyWrapperClass(_ptr) cdef my_c_struct *_ptr = <my_c_struct *>malloc(sizeof(my_c_struct))
if _ptr is NULL:
raise MemoryError
_ptr.a = 0
_ptr.b = 0
return WrapperClass.from_ptr(_ptr)
To then create a ``WrapperClass`` object from an existing ``my_c_struct`` To then create a ``WrapperClass`` object from an existing ``my_c_struct``
pointer, ``PyWrapperClass(ptr)`` can be used. It is possible to create multiple pointer, ``WrapperClass.from_ptr(ptr)`` can be used in Cython code. To allocate
python objects all from the same C pointer which point to the same in-memory a new structure and wrap it at same time, ``WrapperClass.new_struct`` can be
data, if that is wanted, though care must be taken when de-allocating as can used instead.
be seen above with the non-null check. The gil must *not* be released either,
or another lock used if it is, in such cases or race conditions can occur It is possible to create multiple Python objects all from the same pointer
with multiple de-allocations. which point to the same in-memory data, if that is wanted, though care must be
taken when de-allocating as can be seen above.
Attempts to accept ``my_c_struct`` pointers in ``__cinit__`` will result Additionally, the ``ptr_owner`` flag can be used to control which
in errors like:: ``WrapperClass`` object owns the pointer and is responsible for de-allocation -
this is set to ``True`` by default in the example.
The GIL must *not* be released in ``__dealloc__`` either, or another lock used
if it is, in such cases or race conditions can occur with multiple
de-allocations.
Attempts to accept ``my_c_struct`` pointers in ``__cinit__`` will result in
errors like::
Cannot convert 'my_c_struct *' to Python object Cannot convert 'my_c_struct *' to Python object
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment