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.

293voto

Nathan Ostgard Points 3499

Oui, utiliser getattr() pour obtenir l'attribut, et callable() pour vérifier qu'il s'agit bien d'une méthode :

invert_op = getattr(self, "invert_op", None)
if callable(invert_op):
    invert_op(self.path.parent_op)

Il convient de noter que getattr() lève normalement une exception si l'attribut n'existe pas. Cependant, si vous spécifiez une valeur par défaut ( None dans ce cas), il le renverra à la place.

71voto

Antony Points 450

Il fonctionne aussi bien avec Python 2 qu'avec Python 3.

hasattr(connection, 'invert_opt')

hasattr retours True si l'objet de connexion possède une fonction invert_opt définis. Voici la documentation à consulter

https://docs.python.org/2/library/functions.html#hasattr https://docs.python.org/3/library/functions.html#hasattr

22voto

Santa Points 6013

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

Pourquoi êtes-vous contre cela ? Dans la plupart des cas pythoniques, il vaut mieux demander le pardon que la permission ;-)

hasattr est implémenté en appelant getattr et en vérifiant s'il lève, ce qui n'est pas ce que je veux.

Encore une fois, pourquoi ? Ce qui suit est tout à fait pythonique :

    try:
        invert_op = self.invert_op
    except AttributeError:
        pass
    else:
        parent_inverse = invert_op(self.path.parent_op)
        ops.remove(parent_inverse)

Ou bien,

    # if you supply the optional `default` parameter, no exception is thrown
    invert_op = getattr(self, 'invert_op', None)  
    if invert_op is not None:
        parent_inverse = invert_op(self.path.parent_op)
        ops.remove(parent_inverse)

Il convient toutefois de noter que getattr(obj, attr, default) est également implémenté en attrapant une exception. Il n'y a rien de mal à cela au pays de Python !

6voto

Y.H Wong Points 3810

Comme tout ce qui est en Python, si vous essayez assez fort, vous pouvez atteindre les tripes et faire quelque chose de vraiment méchant. Maintenant, voici la partie la plus désagréable :

def invert_op(self, op):
    raise NotImplementedError

def is_invert_op_implemented(self):
    # Only works in CPython 2.x of course
    return self.invert_op.__code__.co_code == 't\x00\x00\x82\x01\x00d\x00\x00S'

S'il vous plaît, faites-nous une faveur, continuez à faire ce que vous avez fait dans votre question et NE PAS n'utilisez jamais ceci à moins que vous ne fassiez partie de l'équipe PyPy en train de pirater l'interpréteur Python. Ce que vous avez là-haut est Python, ce que j'ai ici est pur. MAUVAIS .

4voto

thorwhalen Points 1017

Les réponses ici vérifient si une chaîne est le nom d'un attribut de l'objet. Une étape supplémentaire (en utilisant callable) est nécessaire pour vérifier si l'attribut est une méthode.

La question se résume donc à : quel est le moyen le plus rapide de vérifier si un objet obj possède un attribut attrib. La réponse est

'attrib' in obj.__dict__

Il en est ainsi parce qu'une dictée hache ses clés et que la vérification de l'existence de la clé est donc rapide.

Voir les comparaisons de temps ci-dessous.

>>> class SomeClass():
...         pass
...
>>> obj = SomeClass()
>>>
>>> getattr(obj, "invert_op", None)
>>>
>>> %timeit getattr(obj, "invert_op", None)
1000000 loops, best of 3: 723 ns per loop
>>> %timeit hasattr(obj, "invert_op")
The slowest run took 4.60 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 674 ns per loop
>>> %timeit "invert_op" in obj.__dict__
The slowest run took 12.19 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 3: 176 ns per loop

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