moooeeeep
moooeeeep

Reputation: 32512

What things to be aware of when using the with-statement for own classes?

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

Answers (2)

JS.
JS.

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

Marcin
Marcin

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

Related Questions