Pawel Furmaniak
Pawel Furmaniak

Reputation: 4806

__del__ at program end

Suppose there is a program with a couple of objects living in it at runtime.

Is the __del__ method of each object called when the programs ends?

If yes I could for example do something like this:

class Client:
  __del__( self ):
    disconnect_from_server()

Upvotes: 6

Views: 2670

Answers (4)

jchl
jchl

Reputation: 6532

Yes, the Python interpreter tidies up at shutdown, including calling the __del__ method of every object (except objects that are part of a reference cycle).

Although, as others have pointed out, __del__ methods are very fragile and should be used with caution.

Upvotes: 1

Alex Martelli
Alex Martelli

Reputation: 881715

I second the general idea of using context managers and the with statement instead of relying on __del__ (for much the same reasons one prefers try/finally to finalizer methods in Java, plus one: in Python, the presence of __del__ methods can make cyclic garbage uncollectable).

However, given that the goal is to have "an object that cleans up after itself upon exit or an exception", the implementation by @~unutbu is not correct:

@contextlib.contextmanager
def make_client():
    c=Client()
    yield c
    c.disconnect_from_server()

with make_client() as c:
    ...

If an exception is raised in the ... part, disconnect_from_server_ does not get called (since the exception propagates through make_client, being uncaught there, and therefore terminates it while it's waiting at the yield).

The fix is simple:

@contextlib.contextmanager
def make_client():
    c=Client()
    try: yield c
    finally: c.disconnect_from_server()

Essentially, the with statement lets you almost forget about the good old try/finally statement... except when you're writing context managers with contextlib, and then it's really important to remember it!-)

Upvotes: 6

unutbu
unutbu

Reputation: 879641

There are many potential difficulties associated with using __del__. Usually, it is not necessary, or the best idea to define it yourself.

Instead, if you want an object that cleans up after itself upon exit or an exception, use a context manager:

per Carl's comment:

class Client:
    def __exit__(self,ext_type,exc_value,traceback):
        self.disconnect_from_server()

with Client() as c:
    ...

original answer:

import contextlib

class Client:
    ...

@contextlib.contextmanager
def make_client():
    c=Client()
    yield c
    c.disconnect_from_server()

with make_client() as c:
    ...

Upvotes: 7

phadej
phadej

Reputation: 12123

Consider using with-statement to make cleanup explicit. With circular references __del__ is not called:

class Foo:
  def __del__(self):
    self.p = None
    print "deleting foo"

a = Foo()
b = Foo()
a.p = b
b.p = a

prints nothing.

Upvotes: 2

Related Questions