Общий режим обработки исключений в Python "Правильный путь"
Иногда я нахожусь в ситуации, когда хочу выполнить несколько последовательных команд вроде:
try:
foo(a, b)
except Exception, e:
baz(e)
try:
bar(c, d)
except Exception, e:
baz(e)
...
Эта же картина возникает, когда исключения просто нужно игнорировать.
Это кажется излишним, и чрезмерный синтаксис вызывает на удивление трудность при чтении кода.
В C я бы легко решил этот тип проблемы с помощью макроса, но, к сожалению, это невозможно сделать в прямом питоне.
Вопрос: Как я могу лучше всего уменьшить размер кода и повысить читаемость кода при пересечении этого шаблона?
Ответы
Ответ 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)