strange python destructor behaviour
<p>While playing with OO Python I came across following curiosity. Consider following simple class:</p>

<pre><code>&gt;&gt;&gt; class Monty():
    def __init__(self):
        print 'start m'
    def __del__(self):
        print 'deleted m'
</code></pre>

<p>Instantiating object goes as expected:</p>

<pre><code>&gt;&gt;&gt; a = Monty()
start m
&gt;&gt;&gt; a
&lt;__main__.Monty instance at 0x7fdf9f084830&gt;
</code></pre>

<p>and now the funny part:</p>

<pre><code>&gt;&gt;&gt; del a
&gt;&gt;&gt; a = Monty()
start m
&gt;&gt;&gt; a
deleted m
&lt;__main__.Monty instance at 0x7fdf9f083fc8&gt;
&gt;&gt;&gt; a
&lt;__main__.Monty instance at 0x7fdf9f083fc8&gt;
&gt;&gt;&gt; del a
&gt;&gt;&gt; a = Monty()
start m
&gt;&gt;&gt; del(a)
deleted m
&gt;&gt;&gt; a = Monty()
start m
&gt;&gt;&gt; a
deleted m
&lt;__main__.Monty instance at 0x7fdf9f084830&gt;
</code></pre>

<p>The confusing part here is that I get message from destructor with delay. My understanding is that:</p>

<pre><code>del a
</code></pre>

<p>Deletes object reference so that object a is left for garbage collection. But for some reason interpreter waits with passing message to console. </p>

<p>Another this is the difference between </p>

<pre><code>del x
</code></pre>

<p>and </p>

<pre><code>del(x)
</code></pre>

<p>since if you ran the code using the latter only everything goes as expected - you get immediate info from destructor.</p>

<p>It is possible to reproduce this on Python 2.7 as well as using Python 3.3.</p>

<p>The Python interpreter creates an <em>additional reference</em>. Every time an expression doesn't return <code>None</code>, the result is echoed <strong>and</strong> stored in the <code>_</code> built-in name.</p>

<p>When you then echo a different result, <code>_</code> is rebound to the new result, and the old object reference count drops. In your case, that means that <em>only then</em> is the previous <code>Monty()</code> instance reaped.</p>

<p>In other words, when you execute <code>del a</code>, you are not removing the last reference. Only when you later echo the <em>new</em> object is the last reference gone:</p>

<pre><code>&gt;&gt;&gt; a = Monty()   # reference count 1
start m
&gt;&gt;&gt; a             # _ reference added, count 2
&lt;__main__.Monty instance at 0x7fdf9f084830&gt;    
&gt;&gt;&gt; del a         # reference count down to 1 again
&gt;&gt;&gt; a = Monty()
start m
&gt;&gt;&gt; a             # _ now references the new object, count drops to 0
deleted m         # so the old object is deleted.
&lt;__main__.Monty instance at 0x7fdf9f083fc8&gt;
</code></pre>

<p>You can see the reference by echoing <code>_</code>, and you can clear the reference by echoing something entirely unrelated:</p>

<pre><code>&gt;&gt;&gt; a = Monty()   # reference count 1
start m
&gt;&gt;&gt; a             # echoing, so _ is set and count is now 2
&lt;__main__.Monty instance at 0x1056a2bd8&gt;
&gt;&gt;&gt; _             # see, _ is referencing the same object
&lt;__main__.Monty instance at 0x1056a2bd8&gt;
&gt;&gt;&gt; del a         # reference count down to 1
&gt;&gt;&gt; _             # _ is still referencing the result
&lt;__main__.Monty instance at 0x1056a2bd8&gt;
&gt;&gt;&gt; 'some other expression'    # point to something else
deleted m                      # so reference count is down to 0
'some other expression'
&gt;&gt;&gt; _
'some other expression'
</code></pre>

<p>There is no difference between <code>del x</code> and <code>del(x)</code>. Both execute the <code>del</code> statement, the parentheses are part of the expression and are a no-op in this case. There is no <code>del()</code> function.</p>

<p>The real difference is that you <em>did not echo <code>a</code></em> in that section of the code, so no additional <code>_</code> references were created.</p>

<p>You'd get the exact same results wether or not you use <code>(..)</code> parentheses:</p>

<pre><code>&gt;&gt;&gt; a = Monty()  # ref count 1
start m
&gt;&gt;&gt; del a        # no _ echo reference, so count back to 0
deleted m
&gt;&gt;&gt; a = Monty()  # ref count 1
start m
&gt;&gt;&gt; del(a)       # no _ echo reference, so count back to 0
deleted m
</code></pre>

python oop garbage-collection