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!-)