Documentation bugs in 3.1 - C-API - TypeObjects

D

DreiJane

Hello,

this page http://docs.python.org/3.1/c-api/typeobj.html has a bad
error:

"
PyTypeObject* PyObject.ob_type

This is the type’s type, in other words its metatype. It is
initialized by the argument to the PyObject_HEAD_INIT macro, and its
value should normally be &PyType_Type. However, for dynamically
loadable extension modules that must be usable on Windows (at least),
the compiler complains that this is not a valid initializer.
Therefore, the convention is to pass NULL to the PyObject_HEAD_INIT
macro and to initialize this field explicitly at the start of the
module’s initialization function, before doing anything else. This is
typically done like this:

Foo_Type.ob_type = &PyType_Type;
"

This cannot work, because Foo_Type is no PyObject but a PyVarObject
(independent
of the use of PyVarObject_HEAD_INIT or PyObject_HEAD_INIT). The code
line would
work so:

((PyObject *)&Foo_Type)->ob_type = &PyType_Type

But in the Tutorial for Extensions and Embedding we are advised as
follows:
"
This is so important that we’re going to pick the top of it apart
still further:
PyVarObject_HEAD_INIT(NULL, 0)
This line is a bit of a wart; what we’d like to write is:
PyVarObject_HEAD_INIT(&PyType_Type, 0)
as the type of a type object is “type”, but this isn’t strictly
conforming C and some compilers complain. Fortunately, this member
will be filled in for us by PyType_Ready().
"

What now ?

Another problem, which might be a documentation bug, is the last
sentence here:
"
destructor PyTypeObject.tp_dealloc

A pointer to the instance destructor function. This function must be
defined unless the type guarantees that its instances will never be
deallocated (as is the case for the singletons None and Ellipsis).

The destructor function is called by the Py_DECREF() and Py_XDECREF()
macros when the new reference count is zero. At this point, the
instance is still in existence, but there are no references to it. The
destructor function should free all references which the instance
owns, free all memory buffers owned by the instance (using the freeing
function corresponding to the allocation function used to allocate the
buffer), and finally (as its last action) call the type’s tp_free
function. If the type is not subtypable (doesn’t have the
Py_TPFLAGS_BASETYPE flag bit set), it is permissible to call the
object deallocator directly instead of via tp_free.
"

What ? Where do we "call" these methods ? Primarily we write them down
to get members
of the Foo_Type struct and our question is where. Shall this sentence
mean, that we
write the function, we'd normally use for tp_dealloc und which behaves
like it, to the place of tp_free ?

I've run into terrible trouble with extension classes, which have
neither members nor init.
They work (and i am quite happy about that) but finding out, that
tp_dictoffset had to be
set (for what i wanted) took more than a day of searching - including
öecture of typeobject.c and object.c - and i cannot derive from them.

class(my_extension_class): ... doesn't crash, but results in objects,
which have the type
my_extension_class, what means, that they do not call their __init__.
In certain
circumstances a correct tp_free seems to be a premise for inheritance,
thus i'd very like
to understand the quoted passage.

Joost
 
M

Martin v. Löwis

This cannot work, because Foo_Type is no PyObject but a PyVarObject
(independent
of the use of PyVarObject_HEAD_INIT or PyObject_HEAD_INIT). The code
line would
work so:

((PyObject *)&Foo_Type)->ob_type = &PyType_Type

However, this is not what you should use. Instead, use

Py_Type(&Foo_Type) = &PyType_Type
If the type is not subtypable (doesn’t have the
Py_TPFLAGS_BASETYPE flag bit set), it is permissible to call the
object deallocator directly instead of via tp_free.
"

What ? Where do we "call" these methods ?

You should typically call tp_free inside of tp_dealloc. For example,
string_dealloc ends with

Py_TYPE(op)->tp_free(op);

In the specific case (Py_TYPE(op) is not subtypeable), you could
alternatively also call

PyObject_Del(op);

If there are subclasses, they might have used a different allocator
(rather than the object allocator), hence you must call the deallocator
through tp_free.

HTH,
Martin
 
D

DreiJane

Thanks !

Okay, i've already used the call of tp_free as the last
statement in tp_dealloc and do understand now, that a
call of tp_dealloc should be the last statement in the
code for tp_free in specific cases.

And yes, "Py_Type(&Foo_Type) = &PyType_Type" will be
more stable against changes of the object implementation.
Still there remains the difference to what is told with the
Noddy_Type in the tutorial.

Skimmimg through PyType_Ready in typeobject.c i find,
that

3760 if (Py_TYPE(type) == NULL && base != NULL)
3761 Py_TYPE(type) = Py_TYPE(base);

are the only lines referring to what is ob_type now. Thus
the quoted lines from the tutorial ending with "Fortunately,
this member will be filled in for us by PyType_Ready()."
are possibly wrong (respective outdated) too.

The two lines above are, what happens to my extension
classes, if i want to derive application classes from them.

class(my_extension_class): ...

will of course call more from Python than PyTypeReady,
but PyType(type) = Py_TYPE(base) is not getting corrected
by this "more" here and the class statement doesn't create
a new type. I will examine now, why this happens (without
a crash of the calling application !), but still welcome every
hint. Seen from a strict perspective this is a bug in Python's
C-API. I'll save a freeze of the code for my extension for
anyone, who might interested to reproduce this.

Joost
 
D

DreiJane

Thanks a second time - the picture has
gotten clearer indeed. But for third-party
readers the complexities of this matter
require the correction, that

"Py_Type(&Foo_Type) = &PyType_Type"

must be:
"Py_TYPE(&Foo_Type) = &PyType_Type "

- or am i completely wrong ? Joost
 
M

Martin v. Löwis

DreiJane said:
Thanks a second time - the picture has
gotten clearer indeed. But for third-party
readers the complexities of this matter
require the correction, that

"Py_Type(&Foo_Type) = &PyType_Type"

must be:
"Py_TYPE(&Foo_Type) = &PyType_Type "

- or am i completely wrong ? Joost

No, you are right - I forgot that the spelling had been
changed to upper case.

Regards,
Martin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top