191 votes

Quel est le moyen le plus rapide de vérifier si une classe possède une fonction définie ?

Je suis en train d'écrire un algorithme de recherche dans l'espace d'état de l'IA, et j'ai une classe générique qui peut être utilisée pour implémenter rapidement un algorithme de recherche. Une sous-classe définirait les opérations nécessaires, et l'algorithme ferait le reste.

C'est là que je suis bloqué : Je veux éviter de régénérer l'état parent encore et encore, donc j'ai la fonction suivante, qui renvoie les opérations qui peuvent être légalement appliquées à n'importe quel état :

def get_operations(self, include_parent=True):
    ops = self._get_operations()
    if not include_parent and self.path.parent_op:
        try:
            parent_inverse = self.invert_op(self.path.parent_op)
            ops.remove(parent_inverse)
        except NotImplementedError:
            pass
    return ops

Et la fonction invert_op lance par défaut.

Existe-t-il un moyen plus rapide de vérifier si la fonction n'est pas définie que d'attraper une exception ?

Je pensais à quelque chose comme vérifier la présence dans le répertoire, mais cela ne semble pas correct. hasattr est implémenté en appelant getattr et en vérifiant s'il lève, ce qui n'est pas ce que je veux.

3voto

steveha Points 24808

J'aime la réponse de Nathan Ostgard et je lui ai attribué un vote positif. Mais une autre façon de résoudre votre problème serait d'utiliser un décorateur mémorisant, qui mettrait en cache le résultat de l'appel de la fonction. Ainsi, vous pouvez aller de l'avant et avoir une fonction coûteuse qui calcule quelque chose, mais lorsque vous l'appelez encore et encore, les appels suivants sont rapides ; la version mémorisée de la fonction recherche les arguments dans un dict, trouve le résultat dans le dict à partir du moment où la fonction réelle a calculé le résultat, et renvoie le résultat immédiatement.

Voici une recette pour un décorateur mémorisant appelé "lru_cache" par Raymond Hettinger. Une version de ce décorateur est maintenant standard dans le module functools de Python 3.2.

http://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators/

http://docs.python.org/release/3.2/library/functools.html

1voto

moose Points 4945

Vous pouvez également revoir le cours :

import inspect

def get_methods(cls_):
    methods = inspect.getmembers(cls_, inspect.isfunction)
    return dict(methods)

# Example
class A(object):
    pass

class B(object):
    def foo():
        print('B')

# If you only have an object, you can use `cls_ = obj.__class__`
if 'foo' in get_methods(A):
    print('A has foo')

if 'foo' in get_methods(B):
    print('B has foo')

0voto

Jaroslav Loebl Points 157

Bien que la vérification des attributs dans la propriété __dict__ soit très rapide, vous ne pouvez pas l'utiliser pour les méthodes, car elles n'apparaissent pas dans le hachage __dict__. Vous pouvez cependant recourir à une solution de contournement dans votre classe, si les performances sont si critiques :

class Test():
    def __init__():
        # redefine your method as attribute
        self.custom_method = self.custom_method

    def custom_method(self):
        pass

Vérifier ensuite la méthode comme :

t = Test()
'custom_method' in t.__dict__

Comparaison dans le temps avec getattr :

>>%timeit 'custom_method' in t.__dict__
55.9 ns ± 0.626 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

>>%timeit getattr(t, 'custom_method', None)
116 ns ± 0.765 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Je n'encourage pas cette approche, mais elle semble fonctionner.

[EDIT] L'augmentation des performances est encore plus importante lorsque le nom de la méthode n'est pas dans la classe donnée :

>>%timeit 'rubbish' in t.__dict__
65.5 ns ± 11 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

>>%timeit getattr(t, 'rubbish', None)
385 ns ± 12.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X