Tim Peters <t...@python.org> added the comment:

Well, the refcounts on _everything_ cyclic gc sees are greater than 0.  Because 
if an object's refcount ever falls to 0 in CPython, reference counting deals 
with it immediately, and so it doesn't survive to participate in cyclic gc.

IOW, absolutely everything cyclic gc deals with is "strongly referenced" in the 
sense you're using:  absolutely everything cyclic gc deals with has a nonzero 
refcount.  Indeed, in a debug build, gc asserts early on that everything it 
sees has a refcount > 0.

It can be trash anyway.  Finding those "just internal references" is the 
_point_ of cyclic gc.  In your last example, the instant after you did `del o`, 
the instance of Foo, and the instance of Bar, _both_ became trash, period, 
despite that they both retained positive refcounts.

So you may as well object that the refcount of `self` is also greater than 0 
inside __del__.  Indeed, add

            print(sys.getrefcount(self))

inside your __del__, and you'll see it prints 4.  So it's _twice_ as "strongly 
referenced" as self.value ;-)  It's being destroyed anyway.

Refcounts are simply irrelevant at this point, and so also is the concept of 
"strong reference" on its own.  All that matters is whether a strong reference 
exists from _outside_ the generation being collected.  `self` and `self.value` 
are in exactly the same boat in this regard:  there are no strong references to 
either from outside, but there are strong references to both from inside.  
They're both trash.

There is _a_ principled way to proceed that would get you what you want in this 
example, but CPython never pursued it because it would add major complexity for 
almost no apparent practical gain:  build a graph of all the cyclic trash, 
compute the strongly connected components, build the induced DAG composed of 
the SCCs, then run end-of-life actions in order of a topological sort of that 
DAG.  Then __del__ would run first (self is in a self-cycle SCC with no 
predecessors in the DAG), and the weakref callback second (the Bar instance 
would be in its own SCC, with the `self` SCC as its predecessor in the DAG).

But I'm not sure any real gc system does that.

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue40312>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to