On Aug 27, 2009, at 11:24 AM, Alexey Shamrin wrote:

> Hello!
>
> I am wrapping an open source library with Cython. Hope to release some
> code soon...
>
> First of all, Cython works great for this! It took some time to get
> used to, but soon it became fun to work on a C-Python border! :-)
>
> And now the question.
>
> The C library has structures that I'm wrapping with extension types.
> Here's the code (simplified and without error handling):
>
> cdef extern from "library.h":
>     ctypedef struct lib_obj:
>         int n
>
>     int allocate_obj(lib_obj **obj)
>     void deallocate_obj(lib_obj *obj)
>
> cdef class Object(object):
>     cdef lib_obj *obj
>
>     def __cinit__(self, n):
>         allocate_obj(&self.obj)
>         self.obj.n = n
>
>     def __dealloc__(self):
>         if self.obj:
>             deallocate_obj(self.obj)
>
> Everything is nice so far. But then I had to wrap two more functions
> from "library.h":
>
> cdef extern from "library.h":
>     ...
>     # these functions transfer deallocation responsibility to the  
> caller
>     int copy_obj(lib_obj **dst, lib_obj *src)
>     lib_obj *load_some_obj()
>
> As you can see, I needed to create Object instances not only from
> scratch, but reusing existing lib_obj pointer and skipping memory
> allocation. Plus a nice copy_obj wrapper. After some trial-and-error
> the code became:
>
> cdef class Object(object):
>     cdef lib_obj *obj
>
>     def __cinit__(self, n=None, allocate=True):
>         if allocate:
>             allocate_obj(&self.obj)
>             self.obj.n = n
>
>     def __dealloc__(self):
>         if self.obj:
>             deallocate_obj(self.obj)
>
>     def copy(self):
>         cdef lib_obj *obj
>         copy_obj(&obj, self.obj)
>         o = Object(allocate=False)
>         o.obj = obj
>         return o
>
> cdef Object wrap(lib_obj *obj):
>     Object o
>     o = Object(allocate=False)
>     o.obj = obj
>     return obj
>
> def load_Object():
>     cdef lib_obj *obj = load_some_obj()
>     return wrap(obj)
>
> Well, it works ;-) But can you suggest a nicer way to accomplish  
> this? Problems:
>
> 1. Now I have to handle __cinit__ `allocate` argument in every
> `Object` subclass. It's easy to forget about it -- I'm writing many
> such subclasses.

I don't see how you'd get around this--somewhere you have to give  
that information to the __cinit__ method. Does each subclass have to  
do something extra in __cinit__? It could be wasteful, but the logic  
might be simpler to either always assume it's allocated and  
deallocate in copy and wrap. I don't know what you're doing with  
these things, but if you never wrap None you could use n=None as a  
sentinel to not allocate, only allocating if you're actually wrapping  
something. It's really hard to tell without understanding how it's  
going to be used.

> 2. Notice how I forgot to check for `n` value in __cinit__. One more
> thing to forget...
> 3. I couldn't make `wrap` function a part of `Object` definition. I
> tried to make it a cdef `fromobj` method decorated with @classmethod
> or @staticmethod, but it didn't work.

cdef methods can't (yet) have decorators like this, but a module- 
level function should work fine.

- Robert


_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev

Reply via email to