Antoine Pitrou, 06.08.2013 14:12: > Le Mon, 05 Aug 2013 22:30:29 +0200, > Stefan Behnel a écrit : >> >> Hmm, it's a bit unfortunate that tp_finalize() maps so directly to >> __del__(), but I think this can be fixed. In any case, each >> tp_finalize() function must only ever be called once, so if a subtype >> inherited the tp_finalize() slot from its parent, it mustn't be >> called again. > > This is already dealt with by a custom bit in the GC header (cf. > _PyGC_IS_FINALIZED, IIRC).
But that's only at an instance level. If a type in the hierarchy inherited the slot function for tp_finalize() from its parent, then the child must skip its parent in the call chain to prevent calling the same slot function twice. No instance flag can help you here. >>>> An obvious open question is how to deal with exceptions during >>>> finalisation. Any break in the execution chain would mean that a >>>> part of the type wouldn't be finalised. >>> >>> Let's come back to pure Python: >>> >>> class A: >>> def __del__(self): >>> 1/0 >>> >>> class B(A): >>> def __del__(self): >>> super().__del__() >>> self.cleanup_resources() >> >> What makes you think it's a good idea to call the parent type's >> finaliser before doing the local finalisation, and not the other way >> round? What if the subtype needs access to parts of the super type >> for its cleanup? > > I'm not saying it's a good idea. I'm just saying that to reason about > the C API, it is a good idea to reason about equivalent pure Python > code. Since exceptions aren't implicitly silenced in pure Python code, > they probably shouldn't in C code. > >> In other words, which makes more sense (at the C level): >> >> try: >> super().tp_finalize() >> finally: >> local_cleanup() >> >> or >> >> try: >> local_cleanup() >> finally: >> super().tp_finalize() >> >> Should that order be part of the protocol or not? (well, not for >> __del__() I guess, but maybe for tp_finalize()?) > > No, it is left to the user's preference. Since tp_finalize() is meant > to be equivalent to __del__(), I think it's better if the protocols > aren't subtly different (to the extent to which it is possible, of > course). Ok, fine with me. If the calls are done recursively anyway, then the child can decide when to calls into its parent. >> Coming back to the __del__() vs. tp_finalize() story, if tp_finalize() >> first recursed into the super types, the top-most one of which then >> calls __del__() and returns, we'd get an execution order that runs >> Python-level __del__() methods before C-level tp_finalize() >> functions, but loose the subtype-before-supertype execution order for >> tp_finalize() functions. > > Well... to get that, you'd have to subclass a pure Python class with a > C extension type. Maybe I'm wrong here. It's the default implementation of tp_finalize() that calls __del__, right? If a Python class with a __del__ inherits from an extension type that implements tp_finalize(), then whose tp_finalize() will be executed first? The one of the Python class or the one of the extension type? Stefan _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com