[Pyrex] Cannot cdef __init__?

Paul Prescod paul at prescod.net
Sun Jan 18 19:31:11 CET 2004


Andrew Bennetts wrote:

> On Sat, Jan 17, 2004 at 11:23:16PM -0800, Paul Prescod wrote:
> 
>>If you want to deal with pairs "by reference" deal with Pair objects, 
>>not C pair structs. If you need to interface with C code expecting pair 
>>*'s, you can just extract address of the "p" attribute out of the Pair.
> 
> 
> As far as I can tell, I don't get much choice in this due to the way the
> library I'm experimenting with works.  I'll see if I can rethink the way I
> use it, though.
> 
> Well, I guess it is possible to do this:
> 
> cdef extern from "some_lib.h":
>     void libblah_init_pair(*pair)
> 
> cdef class Foo:
>     cdef pair p
>     
>     # ...
> 
> Then later:
> 
>     f = Foo()
>     libblah_init_pair(&f.p)

There is a much better way. Use the __init__ for Foo to ensure that 
every pair is initialized as soon as it is created. Also, as an aside, 
Python will initialize the pair "p" embedded in the Pair to all zeros so 
if that is what lib_blah_init_pair() is defined to do it may be 
redundant. Also, your Python initializer might set all of the values (x 
and y in this case) so there is nothing for the libblah_init_pair() to 
do at all (assuming it is side-effect free).

> ... I'd rather that
> it was simply impossible to construct a Foo that is only partially
> initialised.

Yes, but you should use the Pyrex/python way of ensuring class 
invariants. Bear in mind that the way I'm describing guarantees an extra 
invariant. No "Pair" object will ever exist with a null pointer for its 
"p". And if you add an __init__ to Foo then you could similarly ensure 
that every Foo initializes its pair.

> And if the library ever returns objects that it has allocated, e.g. via a
> function like:
> 
>     bool_t create_something(...., **Thing, ....);
> 
> i.e. it expects to return a pointer to a newly allocated Thing, then I can't
> do it this way.

In that case you are stuck with pointers and manual memory management. 
But obviously you don't need malloc and free. The library is handling 
construction and destruction for you. Malloc and free are almost never 
useful in Pyrex. You'll want to call the library's deallocator in your 
__del__ method.

I'll append an example using structs by value rather than by reference.

  Paul Prescod


bash-2.05a$ cat foo.h
struct pair{
         int x;
         int y;
};

extern void libblah_init_pair(struct pair *p);

bash-2.05a$ cat andrew.pyx
cdef extern from "foo.h":
     cdef struct pair:
         int x
         int y
     void libblah_init_pair(pair *p)

cdef class Pair:
     cdef pair p
     def __init__(self, x, y):
         libblah_init_pair(&self.p)
         self.p.x = x
         self.p.y = y

cdef class Fred:
     cdef Pair p

     def __init__(self, Pair p):
         self.p = p


def test(a, b):
     return Fred(Pair(a, b))

print test(3, 4)






More information about the Pyrex mailing list