32

是否有更好的方法来执行以下操作:

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

以保持最高效率。

4

6 回答 6

25

对第二个稍作改动看起来非常漂亮和简单。我真的怀疑你会注意到两者之间的任何性能差异,这比嵌套的 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 语句显着减慢你的脚本,脚本结构可能存在更大的问题)

于 2009-03-31T15:50:14.267 回答
22

也许你可以尝试这样的事情:

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)
于 2009-03-31T15:19:15.543 回答
5
method = (
        getattr(a, 'method1', None) or
        getattr(a, 'method2', None) or
        getattr(a, 'method3')
        )
method()

这将首先查找method1,然后method2,然后method3。一旦找到其中一个,搜索将立即停止。如果没有找到任何方法,最后一个getattr将引发异常。

于 2011-11-01T18:53:37.190 回答
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
于 2009-03-31T15:17:52.037 回答
3

紧凑的解决方案:

getattr(a, 'method1',
    getattr(a, 'method2',
        getattr(a, 'method3')))()
于 2011-03-10T07:07:14.807 回答
1

如果您使用的是新式对象:

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__.

编辑:这段代码可能被证明是一团糟。如果__getattribute__或未__dict__找到,请大胆猜测会引发什么样的错误。

于 2009-03-31T15:21:54.977 回答