Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python continue with except if condition not met

I often find myself wanting to do something like this, I have something wrapped in try excepts like this

item= get_item()
try:
    do_work(item)
except SomeError as err:
    if err.code == 123:
        do_something(item)
    else:
        # Actually I don't want to do something with this error code... I want to handle in 'except'
except:
    put_back(item)
    raise

Is there a way to raise into the except block below from the else? (a continue would be nice) I end up doing something like the following which isn't as clean

item= get_item()
try:
    try:
        do_work(item)
    except SomeError as err:
        if err.code == 123:
            do_something(item)
        else:
            raise
 except:
     put_back(item)
     raise

Is there anyway to do that?

like image 466
GP89 Avatar asked Sep 11 '12 17:09

GP89


2 Answers

If you are using a recent enough python version (2.5 and up), you should switch to using a context manager instead:

class WorkItemContextManager(object):
    def __enter__(self):
        self.item = get_item()
        return self.item

    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is not None:
            if exc_type is SomeError and exc_value.code == 123:
                do_something(self.item)
                return True  # Exception handled
            put_back(self.item)

Then:

with WorkItemContextManager() as item:
    do_work(item)

The __exit__ method can return True if an exception has been handled; returning None will instead re-raise any exceptions raised in the with block.

If not, you are looking for a finally block instead:

item = get_item()
try:
    do_work(item)
    item = None
except SomeError as err:
    if err.code == 123:
        do_something(item)
        item = None
finally:
    if item is not None:
        put_back(item)

The finally suite is guaranteed to be executed when the try: suite completes, or an exception has occurred. By setting item to None you basically tell the finally suite everything completed just fine, no need to put it back.

The finally handler takes over from your blanket except handler. If there has been an exception in do_work, item will not be set to None. If the SomeError handler doesn't catch the exception, or err.code is not 123, item will also not be set to None, and thus the put_back(item) method is executed.

like image 167
Martijn Pieters Avatar answered Nov 14 '22 14:11

Martijn Pieters


My suggestion would be to create a function (or series of functions) that wraps the method throwing errors which you'd like to control. Something like...

def wrapper(arg):
    try:      
        do_work(arg)
    except SomeError as e:
        if e.code == 123:
           do_something(item)
           # Other possible cleanup code
        else:
           raise

...then, when you want to call it...

try:
    wrapper(arg)
except SomeError as e:
    put_back(arg)
like image 20
Mark Hildreth Avatar answered Nov 14 '22 14:11

Mark Hildreth