[Pyrex] cdef'd classes initialization

Daniele Varrazzo daniele.varrazzo at gmail.com
Thu Aug 10 12:13:53 UTC 2006


Greg Ewing wrote:
> Lenard Lindstrom wrote:
> 
>> The tp_alloc slot function returns a valid object except for user 
>> defined fields, which are zeroed memory. PyType_GenericNew() makes 
>> the call without doing anything else. So this should be what is 
>> wanted. The problem with Pyrex are C methods. So what is needed is 
>> some kind of extension type specific allocation operation that calls 
>> tp_alloc and sets the vtable field, if any.
> 
> There's also the problem of Python-valued C attributes --
> these are also initialised to None in the tp_new code
> that Pyrex generates. So that would need to be separated
> out somehow as well.
> 
> And then there's also the issue of what happens when
> you derive from another type that needs its tp_new called
> in order to initialise it properly. You can't fully
> separate allocation from initialisation in that case,
> because the tp_alloc call happens at the bottom of the
> chain of tp_new calls. And you can't avoid allocating
> an argument tuple, because tp_new takes Python arguments.

Leonard put me on a promising way with his comment: i don't call 
PyType_GenericNew(), but instead i call the function set by Pyrex in the 
Type tp_new slot.

I refactored my classes splitting what required to create a viewer in 
the __new__() method and what required to build an owner in __init__().

Then i created a factory function createViewer taking the Type of the 
object to create and the pointer to the structure to wrap. Its 
implementation boils down to:

     cdef object createViewer(object t, void *s):
         cdef PyTypeObject *pto
         pto = <PyTypeObject *>t

         cdef Asn1Base o
         o = pto.tp_new(pto, (), {})
         o.setStruct(s)
         return o

the trick is to cast the type object to a PyTypeObject, then i can 
access to its very __new__ method and create an object only initialized 
for what i need.

Some external definition were required:

     cdef extern from "Python.h":

         cdef struct _typeobject

         ctypedef object (*newfunc)(_typeobject *, object, object)

         cdef struct _typeobject:
             newfunc tp_new

         ctypedef _typeobject PyTypeObject

What i obtained is:

  1) from the interpreter only owners can be called: no more forbidden 
options.

  2) the factory provides a fully initialized viewer and is only 
callable by Pyrex code

  3) creating a viewer doesn't involve a Python call

...about all the issues i was concerned about.

All the test suite i prepared with the previous implementation worked 
without glitch. I want to perform some deeper test to check for leaks 
and such.

Does anybody foresee any problem in the approach i am testing? I 
couldn't find documentation about the creation of a type from C: what it 
seems to me is that it is enough to call tp_new to obtain a new object 
(whose space is in turn allocated by tp_alloc) and tp_init to perform 
__init__(). Am i missing something?

Thank you for the many hints,

Daniele



More information about the Pyrex mailing list