instructions try nichés en python?
Question
Y at-il une plus belle façon de faire ce qui suit:
try:
a.method1()
except AttributeError:
try:
a.method2()
except AttributeError:
try:
a.method3()
except AttributeError:
raise
Il semble assez méchant et je préfère ne pas faire:
if hasattr(a, 'method1'):
a.method1()
else if hasattr(a, 'method2'):
a.method2()
else if hasattr(a, 'method3'):
a.method3()
else:
raise AttributeError
pour maintenir une efficacité maximale.
La solution
Peut-être que vous pourriez essayer quelque chose comme ceci:
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
Vous appelez comme ceci:
call_attrs(a, ['method1', 'method2', 'method3'])
va essayer d'appeler les méthodes dans l'ordre où ils sont dans la liste. Si vous voulez passer des arguments, vous pouvez simplement les transmettre après la liste comme ceci:
call_attrs(a, ['method1', 'method2', 'method3'], arg1, arg2)
Autres conseils
Un léger changement à la deuxième semble assez agréable et simple. Je doute vraiment que vous remarquerez une différence de performance entre les deux, ce qui est un peu mieux que d'essayer emboîtés / excepte
def something(a):
for methodname in ['method1', 'method2', 'method3']:
try:
m = getattr(a, methodname)
except AttributeError:
pass
else:
return m()
raise AttributeError
L'autre façon très lisible est de faire ..
def something(a):
try:
return a.method1()
except:
pass
try:
return a.method2()
except:
pass
try:
return a.method3()
except:
pass
raise AttributeError
Bien que longtemps, il est très évident que la fonction fait .. performance ne devrait vraiment pas être un problème (si quelques try / except ralentir votre script vers le bas sensiblement, il y a probablement un plus grand problème avec la structure de script)
method = (
getattr(a, 'method1', None) or
getattr(a, 'method2', None) or
getattr(a, 'method3')
)
method()
Ce sera d'abord chercher method1
, method2
puis, puis method3
. La recherche cessera dès que l'un d'entre eux se trouve. Si aucune des méthodes se trouvent le dernier getattr
déclenche une exception.
Qu'en est-encapsulation des appels dans une fonction?
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
Une solution compacte:
getattr(a, 'method1',
getattr(a, 'method2',
getattr(a, 'method3')))()
Si vous utilisez l'objet nouveau style:
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
Bien sûr, si vous n'utilisez pas un objet nouveau style, vous pouvez essayer __dict__
au lieu de __getattribute__
.
EDIT: Ce code peut se révéler être un gâchis criant. Si __getattribute__
ou __dict__
est introuvable, Devinez sauvage quel type d'erreur est élevé.