Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the python destructor being called?

Tags:

python

When I type this into the interpreter, calling 'y' seems to invoke the destructor?

class SmartPhone:
    def __del__(self):
       print "destroyed"

y = SmartPhone()
y  #prints destroyed, why is that?
y  #object is still there

Here is one run, output does not make sense to me.

C:\Users\z4>python
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> class SmartPhone:
...     def __del__(self):
...        print "destroyed"
...
>>> y = SmartPhone()
>>> del y
destroyed
>>> y = SmartPhone()
>>> y
<__main__.SmartPhone instance at 0x01A7CBC0>
>>> y
<__main__.SmartPhone instance at 0x01A7CBC0>
>>> y
<__main__.SmartPhone instance at 0x01A7CBC0>
>>> del y
>>> y = SmartPhone()
>>> y
destroyed
<__main__.SmartPhone instance at 0x01A7CB98>
>>>

and another, calling 'del y' sometimes calls the destructor and sometimes doesn't

C:\Users\z4>python
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> class SmartPhone:
...     def __del__(self):
...             print "destroyed"
...
>>>
>>> y = SmartPhone()
>>>
>>> y
<__main__.SmartPhone instance at 0x01B6CBE8>
>>> y
<__main__.SmartPhone instance at 0x01B6CBE8>
>>> y
<__main__.SmartPhone instance at 0x01B6CBE8>
>>> del y
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> y = SmartPhone()
>>> y
destroyed
<__main__.SmartPhone instance at 0x01B6CC38>
>>> del y
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>>
like image 741
ppone Avatar asked Jul 10 '13 15:07

ppone


People also ask

Why destructor is called?

Destructors are called when one of the following events occurs: A local (automatic) object with block scope goes out of scope. An object allocated using the new operator is explicitly deallocated using delete . The lifetime of a temporary object ends. A program ends and global or static objects exist.

Is destructor called automatically in Python?

Create Destructor using the __del__() MethodThis method is automatically called by Python when the instance is about to be destroyed. It is also called a finalizer or (improperly) a destructor.

How do you stop a destructor from being called?

The best way to not call a particular destructor is to not create an instance of that object to begin with. Failing that, take the code you don't want to run out of the destructor. I can't conceive any reason why doing this would be legitimate.

Is a destructor always called?

No. You never need to explicitly call a destructor (except with placement new ). A derived class's destructor (whether or not you explicitly define one) automagically invokes the destructors for base class subobjects. Base classes are destructed after member objects.


2 Answers

The output in question is replicated only in interactive shell.

In interactive session, additional variable _ exists, which refer to last value.

Using sys.getrefcount to inspect reference count:

>>> import sys
>>> class SmartPhone:
...     def __del__(self):
...        print "destroyed"
...
>>> y = SmartPhone()
>>> sys.getrefcount(y) # not printed, _ does not reference SmartPhone object yet.
2
>>> y
<__main__.SmartPhone instance at 0x000000000263B588>
>>> sys.getrefcount(y) # y printed, _ reference SmartPhone object.
3

2, 3 in above output should be 1, 2. They are printed that way, because getrefcount() increase reference count temporarily as mentioned in getrefcount documentation.


I changed SmartPhone as follow to make it easy to inspect what's going on.

>>> class SmartPhone(object):
...     def __init__(self, name):
...         self.name = name
...     def __repr__(self):
...         return super(SmartPhone, self).__repr__() + ' name=' + self.name
...     def __del__(self):
...        print "destroyed", self
...
>>> y = SmartPhone('first')
>>> del y # deleted immediately, because only "y" reference it.
destroyed <__main__.SmartPhone object at 0x00000000024FEFD0> name=first
>>> y = SmartPhone('second')
>>> y # at this time, _ reference to second y (y's reference count is now 2)
<__main__.SmartPhone object at 0x00000000024FEFD0> name=second
>>> y
<__main__.SmartPhone object at 0x00000000024FEFD0> name=second
>>> y
<__main__.SmartPhone object at 0x00000000024FEFD0> name=second
>>> del y # not deleted immediately, because _ reference it.
>>> y = SmartPhone('third') # _ still reference the second y, because nothing is printed.
>>> y # second y is deleted, because _ now reference the third y. (no reference to the second y)
destroyed <__main__.SmartPhone object at 0x00000000024FEFD0> name=second
<__main__.SmartPhone object at 0x000000000264A470> name=third
like image 149
falsetru Avatar answered Sep 29 '22 23:09

falsetru


You must have reset the value of y in the same interpreter session, dropping the reference count on the original object to 0. Then, since the first object is not referenced, it gets destroyed, but the new object is referenced by y

>>> class SmartPhone:
...   def __del__(self):
...     print 'destroyed'
...
>>> y = SmartPhone()
>>> y
<__main__.SmartPhone instance at 0x00000000021A5608>
>>> y = SmartPhone()
>>> y
destroyed
<__main__.SmartPhone instance at 0x00000000021A5648>

Notice that the address of these two objects is different. The destroyed that is printed is when __del__ is called on the first instance at 0x00000000021A5608.

In your example, when you explicitly call del on the object reference, it may be destroyed instantly (if this was the only reference to the object and the GC found it immediately). When you do y = SmartPhone() the old object will likely not be destroyed immediately, but will be destroyed when the collector finds it and sees a reference count of 0. This usually happens almost immediately but can be delayed.

Your print 'destroyed' may be displayed immediately or it may display after 1 or more additional commands are executed in your session, but should happen fairly quickly.

like image 28
Brian Avatar answered Sep 30 '22 01:09

Brian