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

Вложенные действия 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

для обеспечения максимальной эффективности.

4b9b3361

Ответ 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__ не найдено, предположите, какая ошибка возникает.