Вложенные действия try в python?
Есть ли лучший способ сделать следующее:
try:
a.method1()
except AttributeError:
try:
a.method2()
except AttributeError:
try:
a.method3()
except AttributeError:
raise
Это выглядит довольно неприятно, и я не хочу этого делать:
if hasattr(a, 'method1'):
a.method1()
else if hasattr(a, 'method2'):
a.method2()
else if hasattr(a, 'method3'):
a.method3()
else:
raise AttributeError
для обеспечения максимальной эффективности.
Ответы
Ответ 1
Возможно, вы могли бы попробовать что-то вроде этого:
def call_attrs(obj, attrs_list, *args):
for attr in attrs_list:
if hasattr(obj, attr):
bound_method = getattr(obj, attr)
return bound_method(*args)
raise AttributeError
Вы бы назвали это следующим образом:
call_attrs(a, ['method1', 'method2', 'method3'])
Это попытается вызвать методы в том порядке, в котором они находятся в списке. Если вы хотите передать любые аргументы, вы можете просто передать их после списка следующим образом:
call_attrs(a, ['method1', 'method2', 'method3'], arg1, arg2)
Ответ 2
Небольшое изменение во втором выглядит довольно красиво и просто. Я действительно сомневаюсь, что вы заметите разницу в производительности между ними, и это немного лучше, чем вложенные try/excepts
def something(a):
for methodname in ['method1', 'method2', 'method3']:
try:
m = getattr(a, methodname)
except AttributeError:
pass
else:
return m()
raise AttributeError
Другой очень читаемый способ - сделать.
def something(a):
try:
return a.method1()
except:
pass
try:
return a.method2()
except:
pass
try:
return a.method3()
except:
pass
raise AttributeError
Пока долго, очень очевидно, что делает функция. Производительность действительно не должна быть проблемой (если несколько try/except операторов заметно замедляют ваш script, вероятно, большая проблема с script)
Ответ 3
method = (
getattr(a, 'method1', None) or
getattr(a, 'method2', None) or
getattr(a, 'method3')
)
method()
Сначала будет искать method1
, затем method2
, затем method3
. Поиск будет остановлен, как только один из них будет найден. Если ни один из методов не найден, последний getattr
вызовет исключение.
Ответ 4
Как насчет инкапсуляции вызовов в функции?
def method_1_2_or_3():
try:
a.method1()
return
except AttributeError:
pass
try:
a.method2()
return
except AttributeError:
pass
try:
a.method3()
except AttributeError:
raise
Ответ 5
Компактное решение:
getattr(a, 'method1',
getattr(a, 'method2',
getattr(a, 'method3')))()
Ответ 6
Если вы используете объект нового стиля:
methods = ('method1','method2','method3')
for method in methods:
try:
b = a.__getattribute__(method)
except AttributeError:
continue
else:
b()
break
else:
# re-raise the AttributeError if nothing has worked
raise AttributeError
Конечно, если вы не используете объект нового стиля, вы можете попробовать __dict__
вместо __getattribute__
.
EDIT: Этот код может оказаться кричащим беспорядком. Если __getattribute__
или __dict__
не найдено, предположите, какая ошибка возникает.