Подтвердить что ты не робот

Общий режим обработки исключений в Python "Правильный путь"

Иногда я нахожусь в ситуации, когда хочу выполнить несколько последовательных команд вроде:

try:
    foo(a, b)
except Exception, e:
    baz(e)
try:
    bar(c, d)
except Exception, e:
    baz(e)
...

Эта же картина возникает, когда исключения просто нужно игнорировать.

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

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

Вопрос: Как я могу лучше всего уменьшить размер кода и повысить читаемость кода при пересечении этого шаблона?

4b9b3361

Ответ 1

Вы можете использовать оператор with если у вас Python 2.5 или выше:

from __future__ import with_statement
import contextlib

@contextlib.contextmanager
def handler():
    try:
        yield
    except Exception, e:
        baz(e)

Ваш пример теперь становится:

with handler():
    foo(a, b)
with handler():
    bar(c, d)

Ответ 2

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

def handle_exception(handler):
    def decorate(func):
        def call_function(*args, **kwargs):
            try:
                func(*args, **kwargs)
            except Exception, e:
                handler(e)
        return call_function
    return decorate

def baz(e):
    print(e)

@handle_exception(baz)
def foo(a, b):
    return a + b

@handle_exception(baz)
def bar(c, d):
    return c.index(d)

Использование:

>>> foo(1, '2')
unsupported operand type(s) for +: 'int' and 'str'
>>> bar('steve', 'cheese')
substring not found

Ответ 3

Если это простые однострочные команды, вы можете их обернуть в lambda s:

for cmd in [
    (lambda: foo (a, b)),
    (lambda: bar (c, d)),
]:
    try:
        cmd ()
    except StandardError, e:
        baz (e)

Вы можете перенести все это в функцию, чтобы она выглядела так:

ignore_errors (baz, [
    (lambda: foo (a, b)),
    (lambda: bar (c, d)),
])

Ответ 4

Лучший подход, который я нашел, - это определить такую ​​функцию:

def handle_exception(function, reaction, *args, **kwargs):
    try:
        result = function(*args, **kwargs)
    except Exception, e:
        result = reaction(e)
    return result

Но это просто не кажется или выглядит правильно на практике:

handle_exception(foo, baz, a, b)
handle_exception(bar, baz, c, d)

Ответ 5

Вы можете попробовать что-то вроде этого. Это смутно C макроподобно.

class TryOrBaz( object ):
    def __init__( self, that ):
        self.that= that
    def __call__( self, *args ):
        try:
            return self.that( *args )
        except Exception, e:
            baz( e )

TryOrBaz( foo )( a, b )
TryOrBaz( bar )( c, d )

Ответ 6

В вашем конкретном случае вы можете сделать это:

try:
    foo(a, b)
    bar(c, d)
except Exception, e:
    baz(e)

Или вы можете поймать исключение на один шаг выше:

try:
    foo_bar() # This function can throw at several places
except Exception, e:
    baz(e)