[Python-Dev] PEP 442 clarification for type hierarchies

Stefan Behnel stefan_ml at behnel.de
Mon Aug 5 21:32:54 CEST 2013

Antoine Pitrou, 05.08.2013 20:56:
> On Sun, 04 Aug 2013 17:59:57 +0200
> Stefan Behnel wrote:
>>> I continued my implementation and found that calling up the base type
>>> hierarchy is essentially the same code as calling up the hierarchy for
>>> tp_dealloc(), so that was easy to adapt to in Cython and is also more
>>> efficient than a generic loop (because it can usually benefit from
>>> inlining). So I'm personally ok with leaving the super type calling code to
>>> the user side, even though manual implementers may not be entirely happy.
>>> I think it should get explicitly documented how subtypes should deal with a
>>> tp_finalize() in (one of the) super types. It's not entirely trivial
>>> because the tp_finalize slot is not guaranteed to be filled for a super
>>> type IIUC, as opposed to tp_dealloc. I assume the recursive invariant that
>>> PyType_Ready() copies it would still hold, though.
> Not only it could be NULL (if no upper type has a finalizer), but it
> could also not exist at all (if Py_TPFLAGS_HAVE_FINALIZE isn't in
> tp_flags). If an API is needed to make this easier then why not. But
> I'm not sure anyone else than Cython really has such concerns. Usually,
> the class hierarchy for C extension types is known at compile-time and
> therefore you know exactly which upper finalizers to call.

Well, you shouldn't have to, though. Otherwise, it would be practically
impossible to insert a new finaliser into an existing hierarchy once other
people/projects have started inheriting from it.

And, sure, Cython makes these things so easy that people actually do them.
The Sage math system has type hierarchies that go up to 10 levels deep
IIRC. That's a lot of space for future changes.

>> Hmm, it seems to me by now that the only safe way of handling this is to
>> let each tp_dealloc() level in the hierarchy call tp_finalize() through
>> PyObject_CallFinalizerFromDealloc(), instead of calling up the stack in
>> tp_finalize(). Otherwise, it's a bit fragile for arbitrary tp_dealloc()
>> functions in base types and subtypes.

I think I got confused here. PyObject_CallFinalizerFromDealloc() works on
the object, not the type. So it can't be used to call anything but the
bottom-most tp_finalize().

> I'm not following you. Why is it "a bit fragile" to call the base
> tp_finalize from a derived tp_finalize? It should actually be totally
> safe, since tp_finalize is a regular function called in a safe
> environment (unlike tp_dealloc and tp_del).

As long as there is not OWTDI, you can't really make safe assumption about
the way a super type's tp_finalize() and tp_dealloc() play together. The
details definitely need to be spelled out here.


More information about the Python-Dev mailing list