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.

Était-ce utile?

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top