Reputation: 4806
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
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
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
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
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