When trying to understand some Python concepts, I encountered the following problem :
def __init__(self, x):
self.x = x
a1 = A()
$ python test.py
Traceback (most recent call last):
File "testdest.py", line 9, in <module>
a1 = A()
TypeError: __init__() takes exactly 2 arguments (1 given)
The error is obvious (missing argument when instantiating), but I wonder why the destructor is called before having an instance?
Unless that when trying to instantiate, Python creates a sort of instance even before calling the constructor and that will need to be cleaned at the end?
self is passed to the constructor, Can I assume this
self is the instance? It that's true, then the instance already exists when calling the constructor, is that right?
Is this a behaviour of the garbage collector that may depend of the current implementation?
From the Python documentation:
Objects are never explicitly destroyed; however, when they become unreachable they may be garbage-collected. An implementation is allowed to postpone garbage collection or omit it altogether — it is a matter of implementation quality how garbage collection is implemented, as long as no objects are collected that are still reachable.
Called after the instance has been created (by new()), but before it is returned to the caller. [...]
Called when the instance is about to be destroyed. [...]
So the object instance already exists when
__init__ is called, as it is created by
__new__. But for Python in general, there is no guarantee that
__del__ will ever be called.
The following only applies to CPython, the reference implementation of Python.
del x doesn’t directly
call x.__del__()— the former decrements the reference count for x by one, and the latter is only called when x‘s reference count reaches zero. [...]
__del__ is called whenever the reference count for the instance drops to 0. This has nothing to do with garbage collection. A little experiment:
>>> class A: ... def __del__(self): print "del" ... >>> a = A() >>> a = None del >>> import gc >>> gc.disable() >>> a = A() >>> a = None del
As you can see, the destructor is called even when GC is explicitly disabled.
Note that this also implies that if you have cycles in your object hierarchy, you end up with objects for which
__del__ never gets called, as the Python GC can't deal with reference cycles.
>>> a1 = A() >>> a2 = A() >>> a1.x = a2 >>> a2.x = a1 >>> a1 = None >>> a2 = None >>> import gc >>> gc.collect() 4 >>> gc.garbage [<__main__.A instance at 0x7f2c66a1d7e8>, <__main__.A instance at 0x7f2c66a1d830>]