getting with statement to deal with various exceptions

Mark Tolonen M8R-yfto6h at mailinator.com
Sun Jul 20 18:50:30 CEST 2008


"mk" <mrkafk at gmail.com> wrote in message 
news:mailman.349.1216557748.922.python-list at python.org...
> Hello,
>
> I'm trying to learn how with statement can be used to avoid writing:
>
> prepare()
> try:
> something_that_can_raise_SomeException()
> except SomeException, err:
> deal_with_SomeException
> finally:
> tear_it_down()
>
> Verbose, not very readable. OK, "with" to the rescue?
>
> Let's take a textbook example from PEP:
>
> with open('/etc/passwd', 'r') as f:
>     BLOCK
>
> Well, great, it's neat that "with" closes the file after BLOCK has 
> finished execution, but what if the file isn't there and attempt to open 
> it raises IOException? I'd like to be able to catch it precisely to avoid 
> writing verbose try: .. except: .. finally: .. blocks which as I 
> understand has been much of the rationale behind creating "with" statement 
> in the first place.
>
> "with" statement only allows easy dealing with prepare() and 
> tear_it_down(). When I try to get it to deal with exceptions that might 
> happen, it becomes more complicated:
>
> class FileContextManager:
> def __enter__(self, filename, mode):
> f = open(filename, mode)
> return f
> def __exit__(self, etype, evalue, etraceback):
> print "etype", etype, "evalue", evalue, "etraceback", etraceback
>
>
> >>> with FileContextManager("somefile", "r") as f:
> a = f.readlines()
>
>
>
> Traceback (most recent call last):
>   File "<pyshell#36>", line 1, in <module>
>     with FileContextManager("somefile", "r") as f:
> TypeError: this constructor takes no arguments
>
>
> Bummer.
>
> Plus, no documentation I've read (on effbot, in PEP 343, etc) says how to 
> deal with the exception happening in __enter__ method of context manager, 
> which is precisely what I'd like to do.
>
> This is only natural, isn't it? When e.g. reading the file, preparation 
> phase is typically checking if it can be opened in the first place. So it 
> falls into __enter__ method of context manager.
>
> "with" limited only to successful execution of a_statement from "with 
> a_statement" seems like limited benefit to me.
>
> I'd like to be able to write smth like
>
> class FileContextManager:
> def __enter__(self, filename, mode):
> f = open(filename, mode)
> return f
> def __except__(IOError, err):
> do_this
> print err
> def __except__(RuntimeError, err):
> do_that
> print "something bad happened", err
> def __exit__(self, etype, evalue, etraceback):
> print "etype", etype, "evalue", evalue, "etraceback", etraceback
>
> __exit__ deals with exceptions happening in the BLOCK below "with" 
> statement, not with exceptions raised in "a_statement", when executing
>
> with a_statement as var:
> BLOCK
>
> In the above way "with" would give me the benefit of more terse, but still 
> understandable and efficient code.
>
> Well, I can always do this:
>
> try:
> with open("somefile.txt") as txtfile:
> for line in txtfile:
> print line
> except IOError:
> print "No such file."
>
>
> No such file.
>
>
> But that's just ugly, nested too many times (flat is better than nested, 
> right?) and not all that more readable.

I just started looking at the with statement myself.  How about:

    from __future__ import with_statement

    class ExceptionManager(object):
        def __enter__(self):
            pass
        def __exit__(self,exc_type,exc_value,tb):
            if exc_type == IOError:
                print 'IOError',exc_value[1]
                return True # suppress it

    with ExceptionManager():
        with open('test.txt') as f:
            f.read()

--
Mark 




More information about the Python-list mailing list