Повторяющиеся пункты «попробуй и за исключением» - PullRequest
11 голосов
/ 22 февраля 2012

Я создал кучу функций, и мне нужно очень похожее, за исключением предложений во всех них, но я ненавижу иметь так много строк try, за исключением предложений и одного и того же кода внутри каждой функции. Например:

import sys
import random

def foo():
    num=random.random()
    try:
        if num>0.5: print 'OK'
        elif num>0.25: raise NameError('Too Small')
        else: raise KeyboardInterrupt
    except NameError:
        print "%s had a NameError" % sys._getframe().f_code.co_name
    except:
        print "%s had a different Error" % sys._getframe().f_code.co_name

def bar():
    num=random.random()
    try:
        if num>0.8: print 'OK'
        elif num>0.6: raise NameError('Too Small')
        else: raise KeyboardInterrupt
    except NameError:
        print "%s had a NameError" % sys._getframe().f_code.co_name
    except:
        print "%s had a different Error" % sys._getframe().f_code.co_name

Код после «try» отличается для функций, но код после «кроме» такой же. Я хочу объединить эти, кроме операторов, чтобы они не делали мой код таким тесным. Есть ли хороший способ сделать это?

Ответы [ 5 ]

22 голосов
/ 22 февраля 2012

Python Decorators - это то, что вы хотите.

Вы сказали, что блок исключений всегда один и тот же.Сделайте собственный декоратор, который делает то, что вы хотите.Вы должны будете применить это к каждой функции / методу, но это точно сохранит дублирование.

def handleError(function):
    def handleProblems():
        try:
            function()
        except Exception:
            print "Oh noes"
    return handleProblems


@handleError
def example():
   raise Exception("Boom!")

При вызове метода с примененным декоратором:

>>> 
>>> example()
Oh noes
>>> 

Вам потребуетсяизмените типы исключений, а также то, что вы делаете, но вы получите суть того, куда я иду с этим.

6 голосов
/ 22 февраля 2012

Содержимое внутри вашего блока try является интересным, поэтому оно должно быть в функциях. Затем просто выберите, какую функцию вы хотите, и вызовите ее, обернутую вашими исключениями. Вы даже можете написать код исключения как функцию и передать выбранную функцию в качестве аргумента. например,

def foo():
    num=random.random()
    if num>0.5: print 'OK'
    elif num>0.25: raise NameError('Too Small')
    else: raise KeyboardInterrupt

def bar():
    num=random.random()
    if num>0.8: print 'OK'
    elif num>0.6: raise NameError('Too Small')
    else: raise KeyboardInterrupt

def try_numerics(f):
    try:
        f()
    except NameError:
        print "%s had a NameError" % sys._getframe().f_code.co_name
    except:
        print "%s had a different Error" % sys._getframe().f_code.co_name

# In your main code...
if (need_to_run_foo):
    try_numerics(foo)
elif (need_to_run_bar):
    try_numerics(bar)
5 голосов
/ 12 июля 2014

Ответ выше не относится к функциям, которые принимают аргументы - для более позднего случая, я думаю, вы хотели бы что-то вроде этого:

def handleError(f):
    def handleProblems(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except Exception:
            print "Oh noes"
    return handleProblems

Мы можем проверить это так:

@handleError
def addTwo(x, y): 
    print(x + y) 

>>> addTwo(5,5)
10
>>> addTwo(5, 's')
Oh noes 
2 голосов
/ 22 февраля 2012

Если это ваши настоящие функции, их было бы легко обобщить.

Вы можете создать одну общую функцию

def general(bottom_num, top_num):
  num=random.random()
  try:
    if num>top_num: print 'OK'
    elif num>bottom_num: raise NameError('Too Small')
    else: raise KeyboardInterrupt
  except NameError:
    print "%s had a NameError" % sys._getframe().f_code.co_name
  except:
    print "%s had a different Error" % sys._getframe().f_code.co_name

это предотвратит повторение вашего кода и решит попытку: кроме: проблемы

0 голосов
/ 12 мая 2017

Я недавно столкнулся с тем же сценарием, в моем случае у меня есть несколько пользовательских исключений, на основе которых мне нужно регистрировать или повышать Исключение дальше. Я создал метод декоратора для обработки исключений в соответствии с типом.

try:
   obj.some_method()
except Exception as e:
    catch_and_log_exception(e)


def catch_and_log_exception(e):
    if isinstance(e, MyConnectionError):
        print "Connection error : %s." % e.message
        sys.exit(1)
    elif isinstance(e, MyConnectionTimeout):
        print "Connection to server has been timed out. %s" % e.message
        sys.exit(1)
    elif isinstance(e, MyException):
        message = e.explanation if e.explanation else e.message
        log_error_message(str(message))
        print "Failed, please check the logs."
        sys.exit(1)
    else:
        raise e

Надеюсь, это поможет !!

...