Initialization and Cleanup¶
Automatic base-class constructor calls.
Calling the base-class constructor first, how to do it using super(), why you should always call it first even if it’s optional when to call it.
__new__() vs. __init__()¶
An excellent example of the subtleties of initialization is static fields in classes.
>>> class Foo(object): ... x = "a" ... >>> Foo.x 'a' >>> f = Foo() >>> f.x 'a' >>> f2 = Foo() >>> f2.x 'a' >>> f2.x = 'b' >>> f.x 'a' >>> Foo.x = 'c' >>> f.x 'c' >>> f2.x 'b' >>> Foo.x = 'd' >>> f2.x 'b' >>> f.x 'd' >>> f3 = Foo() >>> f3.x 'd' >>> Foo.x = 'e' >>> f3.x 'e' >>> f2.x 'b'
If you assign, you get a new one. If it’s modifiable, then unless you assign you are working on a singleton. So a typical pattern is:
class Foo: something = None # Static: visible to all classes def f(self, x): if not self.something: self.something =  # New local version for this object self.something.append(x)
This is not a serious example because you would naturally just
Cleanup happens to globals by setting them to
None (what about locals?).
Does the act of setting them to None cause __del__ to be called, or is
__del__ called by Python before a global is set to None?
Consider the following:
class Counter: Count = 0 # This represents the count of objects of this class def __init__(self, name): self.name = name print name, 'created' Counter.Count += 1 def __del__(self): print self.name, 'deleted' Counter.Count -= 1 if Counter.Count == 0: print 'Last Counter object deleted' else: print Counter.Count, 'Counter objects remaining' x = Counter("First") del x
Without the final del, you get an exception. Shouldn’t the normal cleanup process take care of this?
From the Python docs regarding __del__:
Warning: Due to the precarious circumstances under which __del__() methods are invoked, exceptions that occur during their execution are ignored, and a warning is printed to sys.stderr instead. Also, when __del__() is invoked in response to a module being deleted (e.g., when execution of the program is done), other globals referenced by the __del__() method may already have been deleted. For this reason, __del__() methods should do the absolute minimum needed to maintain external invariants.
Without the explicit call to
__del__ is only called at the end
of the program, Counter and/or Count may have already been GC-ed by the
__del__ is called (the order in which objects are collected is not
deterministic). The exception means that Counter has already been collectd.
You can’t do anything particularly fancy with __del__.
There are two possible solutions here.
1. Use an explicit finalizer method, such as
close()for file objects.
- Use weak references.
Here’s an example of weak references, using a WeakValueDictionary and the trick of mapping id(self) to self:
from weakref import WeakValueDictionary class Counter: _instances = WeakValueDictionary() @property def Count(self): return len(self._instances) def __init__(self, name): self.name = name self._instances[id(self)] = self print name, 'created' def __del__(self): print self.name, 'deleted' if self.Count == 0: print 'Last Counter object deleted' else: print self.Count, 'Counter objects remaining' x = Counter("First")
Now cleanup happens properly without the need for an explicit call to