__del__: when to use it? What happens when you SystemExit/NameError wrt del? Method vs function calls.
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Mon Mar 7 00:56:45 EST 2016
On Monday 07 March 2016 14:27, Veek. M wrote:
> 1. What are the rules for using __del__ besides: 'don't use it'.
__del__ needs to be defined in a class to be called.
It will be called *at some point* when the instance is about to be garbage
collected. There is no guarantee when that will be: it might be instantly,
or a week later.
It may not be called at all, under some obscure circumstances which I don't
remember.
The presence of a __del__ method may prevent the garbage collector from
breaking reference cycles, e.g. if A refers to B, and B refers to A, under
some circumstances if A or B have a __del__ method, the GC may not be able
to break the cycle and neither object will be collected.
At interpreter shutdown, the __del__ method of objects may be called *after*
the resources they are relying on have been deleted. See below.
All of these factors are version- and implementation-dependent. In
particular, remember that IronPython and Jython are based on the .Net CLR
and JVM, so will use completely different garbage collectors than the
CPython garbage collector, and so behave slightly differently.
> 2. What happens when I SystemExit? __del__ and gc are not invoked when I
> SystemExit and there's a circular reference - but why? The OS is going
> to reclaim the memory anyways so why be finicky about circular
> references - why can't we go ahead and call __dell_ and run gc?
I'm sorry, I don't understand the GC well enough to answer that question.
> 3.
> import foo
> def __del__(self, foo=foo):
> foo.bar()
>
> What happens here to prevent a NameError? Apparently without the foo=foo
> a NameError can occur? But why? import foo creates a reference to the
> object anyways so it's refcount will be above 0 anyways till __del__ is
> called.
I assume that you intended the __del__ method to be inside a class.
Let us see what happens without the local reference:
import foo
class X:
def __del__(self):
foo.bar()
instance = X()
sys.exit()
The `import foo` line creates a module level reference to foo. But during
interpreter shutdown, the module references may be deleted before the
__del__ method is called. If that happens, then the code `foo.bar()` will do
a global lookup for `foo`, and not find it, and you will get a NameError.
The way to fix this is to make the class hold onto a reference to foo. Then,
even if the module references are deleted, the class reference won't be.
Either of these ways should work:
class X:
foo = foo # make foo an attribute of the class itself
def __del__(self):
self.foo.bar()
class X:
def __del__(self, foo=foo): # make foo a local variable of the method
foo.bar()
> 4. also, are method calls more efficient than function calls?
No. For technical reasons, methods are a thin wrapper around actual
functions (the "descriptor protocol"). Although it is very fast to create
that wrapper, it is not instantaneous, so methods are not faster than
function calls. The difference is very small though, so it is very rare that
you should need to care about the speed difference. (It is usually dwarfed
by the function body itself.)
Also, remember that attribute lookups are resolved at runtime:
instance.attr.spam.ham.eggs.cheese.foo.bar.baz.foobar()
needs to do nine lookups at runtime. This includes method calls, so try to
avoid long chains of "dots". If you are used to Java, you may need to change
your style of programming:
http://dirtsimple.org/2004/12/python-is-not-java.html
--
Steve
More information about the Python-list
mailing list