I found something interesting, here is a snippet of code:
class A(object):
def __init__(self):
print "A init"
def __del__(self):
print "A del"
class B(object):
a = A()
If I run this code, I will get:
A init
But if I change class B(object)
to class B()
, I will get:
A init
A del
I found a note in the __del__ doc:
It is not guaranteed that del() methods are called for objects that still exist when the interpreter exits.
Then, I guess it's because that B.a
is still referenced(referenced by class B
) when the interpreter exists.
So, I added a del B
before the interpreter exists manually, and then I found a.__del__()
was called.
Now, I am a little confused about that. Why is a.__del__()
called when using old style class? Why do new and old style classes have different behavior?
I found a similar question here, but I think the answers are not clear enough.
TL;DR: this is an old issue in CPython, that was finally fixed in CPython 3.4. Objects kept live by reference cycles that are referred to by module globals are not properly finalized on interpreter exit in CPython versions prior to 3.4. New-style classes have implicit cycles in their
type
instances; old-style classes (of typeclassobj
) do not have implicit reference cycles.Even though fixed in this case, the CPython 3.4 documentation still recommends to not depend on
__del__
being called on interpreter exit - consider yourself warned.New style classes have reference cycles in themselves: most notably
This means that they cannot be deleted instantly*, but only when the garbage collector is run. Since a reference to them is being held by the main module, they will stay in memory until the interpreter shutdown. At the end, during the module clean-up, all the module global names in the main are set to point to
None
, and whichever objects had their reference counts decreased to zero (your old-style class for example) were also deleted. However, the new-style classes, having reference cycles, would not be released/finalized by this.The cyclic garbage collector would not be run at the interpreter exit (which is allowed by the CPython documentation:
Now, old-style classes in Python 2 do not have implicit cycles. When the CPython module cleanup/shutdown code sets the global variables to
None
, the only remaining reference to classB
is dropped; thenB
is deleted, and the last reference toa
is dropped, anda
too is finalized.To demonstrate the fact that the new-style classes have cycles and require a GC sweep, whereas the old-style classes do not, you can try the following program in CPython 2 (CPython 3 does not have old-style classes any more):
With
B
as new-style class as above, the output isWith
B
as old-style class (class B:
), the output isThat is, the new-style class was deleted only after
gc.collect()
even though the last outside reference to it was dropped already; but the old-style class was deleted instantly.Much of this is already fixed in Python 3.4: thanks to PEP 442, which included the module shutdown procedure based on GC code. Now even on interpreter exit the module globals are finalized using the ordinary garbage collection. If you run your program under Python 3.4, the program will print
Whereas with Python <=3.3 it will print
(Do note that other implementations still might or might not execute
__del__
at this moment, regardless of the version of them being above, at, or below, 3.4)