web-dev-qa-db-ja.com

Pythonでネストされたtryステートメント?

以下を行うより良い方法はありますか?

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

最大の効率を維持します。

30
Dan

おそらく、次のようなことを試すことができます。

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)
22
Jason Baker

2番目の部分へのわずかな変更は、見栄えがよくシンプルです。 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ステートメントがスクリプトの速度を著しく低下させる場合は、おそらくスクリプト構造に大きな問題があります)。

24
dbr
method = (
        getattr(a, 'method1', None) or
        getattr(a, 'method2', None) or
        getattr(a, 'method3')
        )
method()

これは最初にmethod1、次にmethod2、次にmethod3を検索します。それらの1つが見つかるとすぐに検索が停止します。メソッドが見つからない場合、最後のgetattrは例外を発生させます。

5
Ethan Furman

呼び出しを関数にカプセル化するのはどうですか?

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
4
unbeknown

コンパクトなソリューション:

getattr(a, 'method1',
    getattr(a, 'method2',
        getattr(a, 'method3')))()
3
Zoetic

新しいスタイルのオブジェクトを使用している場合:

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__が見つかりません。どのようなエラーが発生したかを大まかに推測してください。

1
David Berger