Verschachtelte try-Anweisungen in Python?
Frage
Gibt es eine schönere Art und Weise des folgenden tun:
try:
a.method1()
except AttributeError:
try:
a.method2()
except AttributeError:
try:
a.method3()
except AttributeError:
raise
Es sieht ziemlich böse und ich möchte lieber nicht tun:
if hasattr(a, 'method1'):
a.method1()
else if hasattr(a, 'method2'):
a.method2()
else if hasattr(a, 'method3'):
a.method3()
else:
raise AttributeError
maximale Effizienz zu erhalten.
Lösung
Vielleicht könnten Sie so etwas wie dies versuchen:
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
Sie würde es so nennen:
call_attrs(a, ['method1', 'method2', 'method3'])
Dies wird versuchen, die Methoden in der Reihenfolge nennen sie in in der Liste enthalten sind. Wenn Sie irgendwelche Argumente zu übergeben wollte, könnte man sie gleich nach der Liste übergeben zusammen wie folgt:
call_attrs(a, ['method1', 'method2', 'method3'], arg1, arg2)
Andere Tipps
Eine geringfügige Änderung der zweiten sieht ziemlich schön und einfach. Ich bezweifle wirklich, dass Sie jede Performance-Unterschied zwischen den beiden bemerken, und dies ist ein bisschen schöner als eine verschachtelte try / excepts
def something(a):
for methodname in ['method1', 'method2', 'method3']:
try:
m = getattr(a, methodname)
except AttributeError:
pass
else:
return m()
raise AttributeError
Die andere sehr lesbare Art und Weise ist zu tun ..
def something(a):
try:
return a.method1()
except:
pass
try:
return a.method2()
except:
pass
try:
return a.method3()
except:
pass
raise AttributeError
Während lange, ist es sehr offensichtlich, was die Funktion tun wird .. Leistung sollte wirklich kein Problem sein (wenn ein paar Try / außer Aussagen Skript langsam merklich nach unten, gibt es wahrscheinlich ein größeres Problem mit der Skript Struktur)
method = (
getattr(a, 'method1', None) or
getattr(a, 'method2', None) or
getattr(a, 'method3')
)
method()
Dies wird zuerst sucht method1
, dann method2
, dann method3
. Die Suche wird beendet, sobald einer von ihnen gefunden wird. Wenn keine der Methoden der letzte getattr
erhöhen wird eine Ausnahme zu finden ist.
Wie wäre es, die Anrufe in einer Funktion Einkapseln?
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
Eine kompakte Lösung:
getattr(a, 'method1',
getattr(a, 'method2',
getattr(a, 'method3')))()
Wenn Sie mit neuem Stil Objekt:
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
Natürlich, wenn Sie keinen neuen Stil Objekt verwenden, können Sie __dict__
statt __getattribute__
versuchen.
EDIT: Dieser Code könnte sich ein Schreien Einander. Wenn __getattribute__
oder __dict__
nicht gefunden wird, nehmen eine wilde erraten, welche Art von Fehler ausgelöst wird.