I am working on a Cython interface to a C library. I have this class:
cdef class CholeskyFactor: cdef cholmod_factor *_factor # ... etc. def __cinit__(self, A, *, order=None, **kwargs): # allocate and set factor to non-null value self._factor = create_cholmod_factor(A, order) I'd like to create a .copy() method for the class. Since _factor is a pointer to an underlying C data structure, I can't just use import copy; copy.deepcopy(). In order to create a copy, I would like to instantiate a "blank" version of my class, then call a C function to copy over the memory appropriately:
def copy(self): cdef CholeskyFactor cf = CholeksyFactor.__new__(CholeskyFactor) cf._factor = cholmod_copy_factor(self._factor) # ... etc. copy other members return cf In order for the object to be in a "safe" (and usable) state where self._factor != NULL, we need a non-null A argument to the constructor. To create the copy, we need a "blank" constructor with A=None that sets self._factor = NULL and returns. The issue, however, is that the "blank" constructor leaves the object in a non-safe state with self._factor = NULL:
# Blank constructor def __cinit__(self, A=None, **kwargs): self._factor = NULL if A is None: return else: self._factor = create_cholmod_factor(A, order) # ... etc. It seems like my only option is to allow A=None in __cinit__, and add an inline check to every property and method in the class that raises ValueError and tells the user to instantiate with CholeskyFactor(A) instead.
Is there some way I haven't found in Cython documentation to instantiate a "blank" object without calling __cinit__? Or a more idiomatic way to prevent users from instantiating the class directly without the A argument (and thus leaving it in an un-safe state)?