Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exceptions for the whole class

I'm writing a program in Python, and nearly every method im my class is written like this:

def someMethod(self):
    try:
       #...
    except someException:
       #in case of exception, do something here

       #e.g display a dialog box to inform the user 
       #that he has done something wrong

As the class grows, it is a little bit annoying to write the same try-except block over and over. Is it possible to create some sort of 'global' exception for the whole class? What's the recommended way in Python to deal with this?

like image 899
user2494129 Avatar asked Oct 07 '13 18:10

user2494129


2 Answers

Write one or more exception handler functions that, given a function and the exception raised in it, does what you want to do (e.g. displays an alert). If you need more than one, write them.

def message(func, e):
    print "Exception", type(e).__name__, "in", func.__name__
    print str(e)

Now write a decorator that applies a given handler to a called function:

import functools

def handle_with(handler, *exceptions):
    try:
        handler, cleanup = handler
    except TypeError:
        cleanup = lambda f, e: None
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except exceptions or Exception as e:
                return handler(func, e)
            else:
                e = None
            finally:
                cleanup(func, e)
        return wrapper
    return decorator

This only captures the exceptions you specify. If you don't specify any, Exception is caught. Additionally, the first argument can be a tuple (or other sequence) of two handler functions; the second handler, if given, is called in a finally clause. The value returned from the primary handler is returned as the value of the function call.

Now, given the above, you can write:

@handle_with(message, TypeError, ValueError)
def add(x, y):
    return x + y

You could also do this with a context manager:

from contextlib import contextmanager 

@contextmanager
def handler(handler, *exceptions):
    try:
        handler, cleanup = handler
    except TypeError:
        cleanup = lambda e: None
    try:
        yield
    except exceptions or Exception as e:
        handler(e)
    else:
        e = None
    finally:
        cleanup(e)

Now you can write:

def message(e):
    print "Exception", type(e).__name__
    print str(e)

 def add(x, y):
     with handler(message, TypeError, ValueError):
         return x + y

Note that the context manager doesn't know what function it's in (you can find this out, sorta, using inspect, though this is "magic" so I didn't do it) so it gives you a little less useful information. Also, the context manager doesn't give you the opportunity to return anything in your handler.

like image 66
kindall Avatar answered Oct 13 '22 11:10

kindall


I can think of two options:

  1. Write a decorator that can wrap each method in the try block.
  2. Write a "dispatcher" method that calls the appropriate method inside a try block, then call that method instead of the individual ones. That is, instead of calling obj.someMethod(), obj.otherMethod, you call obj.dispatch('someMethod') or obj.dispatch('otherMethod'), where dispatch is a wrapper that contains the try block.

Your approach seems like a bit of a strange design, though. It might make more sense to have the dialog-box stuff in some other part of the code, some higher-level event loop that catches errors and displays messages about them.

like image 3
BrenBarn Avatar answered Oct 13 '22 12:10

BrenBarn