Reputation: 32512
I am planning to implement C++-like constructor/destructor functionality to one of my Python classes using the handy with statement. I've come accross this statement only for file IO up to now, but I thought it would be rather helpful for connection-based communication tasks as well, say sockets or database connections. Things that eventually need to be closed.
In PEP 343 (linked above) it is said, that with
needs the methods __enter__
and __exit__
, and my straight-forward implementation of this appears to work as intended.
class MyConnection:
def __init__(self):
pass
def __enter__(self):
print "constructor"
# TODO: open connections and stuff
# make the connection available in the with-block
return self
def __exit__(self, *args):
print "destructor"
# TODO: close connections and stuff
with MyConnection() as c:
# TODO: do something with c
pass
Which yields the output (as expected):
constructor
destructor
Should it really be this easy? What are the things to consider besides this? Why do so many libraries (apparantly) lack this functionality yet? Have I missed something?
Upvotes: 8
Views: 167
Reputation: 16097
One issue I have run into while attempting to implement 'with' functionality in my libraries is figuring out an elegant way to handle failure exceptions. Given the following:
class open_file_for_read(object):
def __init__(self):
self.filename = "./does_not_exist.txt"
self.fileobj = None
def __enter__(self):
print("Opening file %s for read" % self.filename)
self.fileobj = open(name=self.filename, mode='r')
return self.fileobj
def __exit__(self, type, value, traceback):
self.fileobj.close()
with open_file_for_read() as fh:
for li in fh.readlines():
print(li)
What is the recommended method for handling the inevitable "IOError: [Errno 2] No such file or directory: './does_not_exist.txt'" exception? There's always the 'try/except' approach
try:
with open_file_for_read() as fh:
except IOError:
...
except XXX:
...
...
This direct approach works, but I think it detracts from the simplicity of using the 'with' construct. Perhaps someone out there has a more elegant solution?
Appologies for this being more of a question than an answer, but it is one of the issues I've run into when attempting to implement 'with'.
Upvotes: 0
Reputation: 49826
(a) It's that easy
(b) An alternative approach is a decorator function, which decorates functions (and classes, but not for this use-case), and also allows code to be called both before and after the wrapped function. Those seem slightly more common.
(c) I don't think you're missing anything.
Upvotes: 5