GP89
GP89

Reputation: 6730

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?

Upvotes: 9

Views: 16900

Answers (4)

jpmc26
jpmc26

Reputation: 29874

Context managers are excellent, but for some simple cases where you won't be reusing the logic anywhere else, they can be a bit heavy.

Instead of trying to have multiple except blocks, you can just test the exception inside a single except block:

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

Note that this is pretty much what a context manager's __exit__ method ends up looking like, anyway.

Be wary that code that really belongs in finally doesn't end up here.

Upvotes: 2

Martijn Pieters
Martijn Pieters

Reputation: 1121992

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.

Upvotes: 9

Mark Hildreth
Mark Hildreth

Reputation: 43071

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)

Upvotes: 2

guyrt
guyrt

Reputation: 927

It's good to keep in mind what try-except flow is for, and one of their advantages is that they remove the need for status variables and status checks like

if not foo:
    # do something

Also, an Exception class should represent a specific kind of error. If you need to make further decisions about the kind of error in an except block, it's a good sign that the class isn't specific enough to represent the program state. Your best bet is to subclass SomeError and only catch the subclass in the first except. Then other instances of SomeError will fall through to the second except block.

Upvotes: 1

Related Questions