2014-11-04 3 views
2

У меня есть повторяющийся набор длинных блоков try/except1/except2/etc в серии методов класса, которые отличаются только внешним методом класса, вызываемым внешним экземпляром класса. Ниже представлена ​​упрощенная версия (есть на самом деле 4 исключения, которые я обработка и восемь методов, отличающееся только метод экземпляра, который называется):В python 2.7, как я могу обернуть метод экземпляра класса или украсить его блоком try/except?

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 ... 

Я пытался различными способами конденсации этого кода, пытаясь обернуть два оператора в части try: часть кода с помощью вложенных функций, декораторов и т. д., но, похоже, не работают из-за того, что мне трудно переводить другие примеры из-за: 1) я создаю экземпляр класса, который вам нужен для использования позже в одном из исключающих блоков и 2) я вызываю метод экземпляра и 3) мне нужно вернуть результат метода экземпляра.

Есть ли способ выполнить это с частичным из functools или дескрипторов или любым другим способом? У меня есть неуклюжая реализация в настоящее время с расширенным блоком if/elif, который выбирает метод экземпляра на основе целочисленного кода, который я использую в функции обертки, но думаю, что должен быть более элегантный способ. Я относительно новичок в Python и не понимаю ...

ответ

2

Вы можете использовать фабрику функций (т. Е. Функцию, возвращающую функцию).

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') 

make_method Передано внешним способом имя в виде строки. getattr используется (внутри method), чтобы получить фактический метод от x с учетом строки methname. getattr(x, 'foo') эквивалентно x.foo.

* в def method(self, *args) сообщает Python, что method может принимать произвольное количество позиционных аргументов. Внутри method, args это кортеж. В * в y = getattr(x, methname)(*args) Python передает элементы в args как отдельные аргументы методу, возвращенному getattr(x, methname). Оператор распаковки * объясняется в the docs, here, а также в this blog.