Повторяющиеся попытки и исключения

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

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" отличается для функций, но код после "except" одинаковый. Я хочу консолидировать эти исключения, чтобы они не заставляли мой код выглядеть настолько стесненным. Есть ли хороший способ сделать это?

Ответ 1

Декораторы Python - это то, что вы хотите.

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

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


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

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

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

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

Ответ 2

Содержимое внутри вашего блока 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)

Ответ 3

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

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 

Ответ 4

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

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

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

это не позволит повторить код и повторить попытку: except: issue

Ответ 5

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

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

Надеюсь на эту помощь!