Tim Peters <t...@python.org> added the comment:
This won't go anywhere without code (preferably minimal) we can run to reproduce the complaint. If there were a "general principle" at work here, someone else would surely have reported it over the last few decades ;-) To the contrary, the common confusion is in the _other_ direction: a weakref callback _not_ getting invoked when a programmer thinks it "should be". The cause for that is always the same: the weakref object died before the weakly referenced object died. That was the primary motivation for introducing `weakref.finalize()`. CPython does not, in general, "batch" (or in any other way delay) object destruction. An object is destroyed - immediately - when its refcount falls to 0. In a technical sense, that's also true in the case of cycles (in which case the gc module artificially drives refcounts to 0, based on liveness and reachability analysis). With very few exceptions, neither does it hang on to "hidden" references. The primary exception to that is in interactive shells, where the module-global identifier "_" is typically bound, by magic, to the object most recently displayed. In the case of exceptions, it's also possible for programs to accidentally hang on to the exception object, from which the entire chain of stack frames back to the source of the exception can be reached. So, based on what you said, this is the best attempt I can make: import sys, weakref class C: def __del__(self): print("__del__ called") def wrcb(x): print("weakref callback called") c = C() d = {"x" : weakref.ref(c, wrcb)} print(sys.getrefcount(d["x"])) #del d["x"] del c which displays: 2 __del__ called weakref callback called Note the 2! If the moral equivalent in your code displays a number larger than 2, then there are more references to the weakref object than just as a dict value (that's one; the other reference comes from temporarily incrementing the refcount of `d["x"]` to pass it as an argument to `getrefcount()`). If I uncomment the penultimate line, to destroy the weakref before `c` is destroyed, the output changes to: 2 __del__ called So it's all as expected. Can you change that code to demonstrate your case? ---------- nosy: +tim.peters _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue43383> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com