KenV99
KenV99

Reputation: 195

In python 2.7, how can I wrap a class instance method or decorate it with a try/except block?

I have a repeating set of lengthy try/except1/except2/etc blocks in a series of class methods that only differ by the outside class method being called on an outside class instance. Below is a simplified version (there are actually 4 exceptions that I am handling and eight methods that only differ by the instance method being called):

class MyClass(object):
    def __init__(self):
        self.arg = 'foo'

    def method1(self, arg1):
        err = -1
        y = None
        try:
            x = AnOutsideClass(self.arg)     # Creates a class instance of an imported class
            y = x.outsideclassmethod1(arg1)  # Calls an instance method that returns another different class instance
        except MyException1:
            x.dosomething() # Needed to handle error
        except MyException2:
            err = 0
        finally:
            del x
        return y, err

    def method2(self, arg1, arg2, arg3):
        err = -1
        y = None
        try:
            x = AnOutsideClass(self.arg)
            y = x.outsideclassmethod2(arg1, arg2, arg3)  # This is the only thing changed
                                                         # A different method with different argument requirements
        except MyException1:
            x.dosomething()
        except MyException2:
            err = 0
        finally:
            del x
        return y, err

    def method3 ...

I have been trying various ways of condensing this code by trying to wrap the two statements in the try: portion of the code by using nested functions, decorators, etc, but seem to fail due to the fact that I am have trouble translating other examples of this due to: 1) am creating a class instance that needs to be used later in one of the except blocks and 2) am calling an instance method and 3) I need to return the result of the instance method.

Is there anyway of accomplishing this with partial from functools or descriptors or any other means? I have a clunky implementation currently with an extended if/elif block that picks the instance method based on an integer code that I use in a wrapper function, but am thinking there must be a more elegant way. I am relatively new to Python and am at a loss...

Upvotes: 2

Views: 687

Answers (1)

unutbu
unutbu

Reputation: 879691

You could use a function factory (i.e., a function that returns a function).

def make_method(methname):
    def method(self, *args):
        err = -1
        y = None
        try:
            x = AnOutsideClass(self.arg)     # Creates a class instance of an imported class
            y = getattr(x, methname)(*args)  # Calls an instance method that returns another different class instance
        except MyException1:
            x.dosomething() # Needed to handle error
        except MyException2:
            err = 0
        finally:
            del x
        return y, err
    return method

class MyClass(object):
    def __init__(self):
        self.arg = 'foo'
    method1 = make_method('outsideclassmethod1')
    method2 = make_method('outsideclassmethod2')

The make_method is passed the outside method name as a string. getattr is used (inside method) to get the actual method from x given the string methname. getattr(x, 'foo') is equivalent to x.foo.

The * in def method(self, *args) tells Python that method can accept an arbitrary number of positional arguments. Inside method, args is a tuple. The * in y = getattr(x, methname)(*args) tells Python to pass the elements in args as individual arguments to the method returned by getattr(x, methname). The * unpacking operator is explained in the docs, here, and also in this blog.

Upvotes: 2

Related Questions