J'écris un algorithme de recherche d'espace d'état AI, 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 s'occupe du reste.
Voici où je suis bloqué: je veux éviter de régénérer l'état parent encore et encore, j'ai donc 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 de détecter une exception?
Je pensais à quelque chose sur la vérification du présent dans dir, mais cela ne semble pas correct. hasattr est implémenté en appelant getattr et en vérifiant s'il déclenche, ce qui n'est pas ce que je veux.
has_op = lambda obj, op: callable(getattr(obj, op, None))
hasattr(connection, 'invert_opt')
.Réponses:
Oui, utilisez
getattr()
pour obtenir l'attribut etcallable()
pour vérifier qu'il s'agit d'une méthode:Notez que
getattr()
lève normalement une exception lorsque l'attribut n'existe pas. Cependant, si vous spécifiez une valeur par défaut (None
dans ce cas), il la renverra à la place.la source
getattr
dans ce cas intercepte une exception silencieusement et renvoie la valeur par défaut à la place, tout comme lehasattr
fait, ce que l'OP était pour une raison quelconque contre.Cela fonctionne à la fois en Python 2 et Python 3
hasattr
retourneTrue
si l'objet de connexion a une fonctioninvert_opt
définie. Voici la documentation pour vous faire paîtrehttps://docs.python.org/2/library/functions.html#hasattr https://docs.python.org/3/library/functions.html#hasattr
la source
connection.invert_opt = 'foo'
.Pourquoi êtes-vous contre ça? Dans la plupart des cas pythoniques, il vaut mieux demander pardon que la permission. ;-)
Encore une fois, pourquoi cela? Ce qui suit est assez pythonique:
Ou,
Notez, cependant, que cela
getattr(obj, attr, default)
est essentiellement implémenté en interceptant une exception. Il n'y a rien de mal à cela dans le pays Python!la source
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.
Cela se résume donc à: quel est le moyen le plus rapide de vérifier si un objet obj a un attribut attrib. La réponse est
Il en est ainsi parce qu'un dict hache ses clés, donc la vérification de l'existence de la clé est rapide.
Voir les comparaisons de temps ci-dessous.
la source
__slots__
.__slots__
Aide à accélérer l'accès aux attributs d'environ 10%. stackoverflow.com/a/14119024/1459669J'aime la réponse de Nathan Ostgard et je l'ai votée à la hausse. Mais une autre façon de résoudre votre problème serait d'utiliser un décorateur de mémorisation, qui mettrait en cache le résultat de l'appel de fonction. Ainsi, vous pouvez aller de l'avant et avoir une fonction coûteuse qui comprend 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émo appelé "lru_cache" par Raymond Hettinger. Une version de ceci est désormais 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
la source
Comme n'importe quoi en Python, si vous essayez assez fort, vous pouvez vous attaquer aux tripes et faire quelque chose de vraiment méchant. Maintenant, voici la partie la plus méchante:
S'il vous plaît, faites-nous une faveur, continuez simplement à faire ce que vous avez dans votre question et ne l' utilisez jamais à moins que vous ne fassiez partie de l'équipe PyPy en train de pirater l'interpréteur Python. Ce que vous avez là-haut, c'est Pythonic, ce que j'ai ici est du mal pur .
la source
co_names
est égal à('NotImplementedError',)
. Cependant, je ne suis pas sûr que cela en fasse plus ou moins mal.Vous pouvez également parcourir la classe:
la source
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 piratée dans votre classe, si les performances sont si critiques:
Ensuite, vérifiez la méthode comme:
Comparaison du temps avec
getattr
:Non pas que j'encourage cette approche, mais cela semble fonctionner.
[EDIT] L'amélioration des performances est encore plus élevée lorsque le nom de la méthode n'est pas dans une classe donnée:
la source
__dict__
pourrait être annulée. On ne peut pas y faire confiance.