[Python-Dev] PEP 442 clarification for type hierarchies (original) (raw)

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 tpdealloc(), 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 tpfinalize() in (one of the) super types. It's not entirely trivial because the tpfinalize slot is not guaranteed to be filled for a super type IIUC, as opposed to tpdealloc. I assume the recursive invariant that PyTypeReady() 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 PyTPFLAGSHAVEFINALIZE isn't in tpflags). 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 tpdealloc() level in the hierarchy call tpfinalize() through PyObjectCallFinalizerFromDealloc(), instead of calling up the stack in tpfinalize(). Otherwise, it's a bit fragile for arbitrary tpdealloc() 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 tpfinalize from a derived tpfinalize? It should actually be totally safe, since tpfinalize is a regular function called in a safe environment (unlike tpdealloc and tpdel).

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.

Stefan



More information about the Python-Dev mailing list