Ivan Mishalkin
Ivan Mishalkin

Reputation: 1108

Python objects in dealloc in Cython

In the documentation it is written that "Any C data that you explicitly allocated (e.g., via malloc) in your _cinit_() method should be freed in your _dealloc_() method."

This is not my case. I have following extension class:

cdef class SomeClass:
    cdef dict data
    cdef void * u_data

    def __init__(self, data_len):
        self.data = {'columns': []}
        if data_len > 0:
            self.data.update({'data': deque(maxlen=data_len)})
        else:
            self.data.update({'data': []})
        self.u_data = <void *>self.data

    @property
    def data(self):
        return self.data

    @data.setter
    def data(self, new_val: dict):
        self.data = new_val

Some C function has an access to this class and it appends some data to SomeClass().data dict. What should I write in __dealloc__, when I want to delete the instance of the SomeClass()?

Maybe something like:

def __dealloc__(self):
    self.data = None
    free(self.u_data)

Or isn't there any need to dealloc anything at all?

Upvotes: 3

Views: 1691

Answers (1)

DavidW
DavidW

Reputation: 30889

No you don't need to and no you shouldn't. From the documentation

You need to be careful what you do in a __dealloc__() method. By the time your __dealloc__() method is called, the object may already have been partially destroyed and may not be in a valid state as far as Python is concerned, so you should avoid invoking any Python operations which might touch the object. In particular, don’t call any other methods of the object or do anything which might cause the object to be resurrected. It’s best if you stick to just deallocating C data.

You don’t need to worry about deallocating Python attributes of your object, because that will be done for you by Cython after your __dealloc__() method returns.


You can confirm this by inspecting the C code (you need to look at the full code, not just the annotated HTML). There's an autogenerated function __pyx_tp_dealloc_9someclass_SomeClass (name may vary slightly depending on what you called your module) does a range of things including:

__pyx_pw_9someclass_9SomeClass_3__dealloc__(o);
/* some other code */
Py_CLEAR(p->data);

where the function __pyx_pw_9someclass_9SomeClass_3__dealloc__ is (a wrapper for) your user-defined __dealloc__. Py_CLEAR will ensure that data is appropriately reference-counted then set to NULL.

It's a little hard to follow because it all goes through several layers of wrappers, but you can confirm that it does what the documentation says.

Upvotes: 5

Related Questions