In Python, how do I determine if an object still exists?
The gc
module is the way to debug this kind of information. For example:
import gc
a = [1, 2, 3]
b = [a, a]
gc.collect()
refs = gc.get_referrers(a)
We know the a
variable itself refers to the object. Or, more accurately, the globals of the __main__
module have refer to that object, under the value associated with the key a
. But are there any other refs?
print(len(refs))
print(refs)
This prints 2
. And then, in addition to printing the module's globals, it also prints out [[1, 2, 3], [1, 2, 3]]
, the value of b
.
So, if you know how many references to the object will exist beside the one you're looking for (much trickier in real life than in a trivial example), or you have some way of identifying the value that you're trying to check, gc.get_referrers
can do what you want. If you don't know either of those, there's really know way to figure it out short of by picking through the whole referrers list and trying to figure it out, which gets very hard.
An alternative way to do this, of course, is to provide a function that walks your data structures and searches for the value you were looking for. This can be difficult or even impossible for some structures, but if you can do it, it's often worth doing for all kinds of debugging reasons, not just this one.
Or, of course, if you can add a __del__
method to your object, you can prove that it no longer exists (by logging a call to its __del__
), but that doesn't help prove that it does exist (it may have no live referents, but not have been collected yet… in fact, just adding a __del__
may prevent it from being collected, if it's in a cycle).
This is in no way a solution you should use in any sort of a production setting, (largely because it typically ends up throwing a segfault) but for debugging purposes you can use the following snippet of code to access a variable by its id to determine if it still exists. (Snippet from here)
>>> import ctypes, gc
>>> a = "hello world"
>>> id(a)
7696579801024
>>> len(gc.get_referrers(a))
1
>>> li = [a]
>>> len(gc.get_referrers(a))
2
>>> del a
>>> print ctypes.cast(7696579801024, ctypes.py_object).value
hello world
>>> len(gc.get_referrers(ctypes.cast(7696579801024, ctypes.py_object).value))
1
>>> del li
>>> print ctypes.cast(7696579801024, ctypes.py_object).value
Segmentation fault (core dumped)
Essentially, ctypes inability to return the object after it's last referrer was deleted implies that it no longer exists.
I stress again though, this is in no way a sure-fire testing method nor suitable for a production setting. Aside from the segfaults, ctypes could also return some other object (constructed using the garbage that is left in its place). It is also feasible that it could return the same object even after its garbage collection if the bytes in its memory location haven't changed. I haven't witnessed this myself, but I don't see why it wouldn't be possible.
You can create a weak reference to an object and then check if that reference can still be resolved:
import weakref
class Foo:
pass
foo = Foo()
foo_ref = weakref.ref(foo)
print(foo_ref()) # Prints something like: <__main__.Foo instance at 0x7f7180895a28>
del foo
print(foo_ref()) # Prints: None
For an in-depth exploration or what is keeping your object alive, you can use objgraph:
import objgraph
x = []
y = [x, [x], dict(x=x)]
objgraph.show_backrefs([x], filename='sample-backref-graph.png')