7
votes

En utilisant appelable (x) vs. hasattr (x, "__call__")

J'écris Python qui cible versions 3.2 et plus. On dirait que l'utilisation de la fonction intégrée appelable est le moyen le plus simple et le plus efficace de le faire. J'ai vu des recommandations pour hasattr (x, "__call __") code>, collections.callable (x) code>, et simplement utiliser essayer / sauf code> une tentative d'appel.

J'ai testé des éléments appelables (une classe et une fonction), en utilisant Timeiit code> avec 100 000 itérations; Dans les deux cas utilisant appelable ne prend que 75% du temps de vérification de l'attribut. Lorsque l'élément n'est pas appelable (un entier et une chaîne) en utilisant des séjours appelables au même coût qu'un class ou une fonction lors de la vérification de l'attribut est d'environ 2,3 fois plus cher que pour une classe ou une fonction. Je ne m'attendais pas à cette différence, mais elle favorise également le clair et concis Appelable (X) code> approche. P>

Mais je suis relativement nouveau à Python et qu'aucun expert, il en va de même. Il y a des raisons pour lesquelles je ne suis pas au courant que je devrais utiliser l'approche Hasattr ou une autre approche? P>

FWIW, les résultats des différents trimestres suivent. Le premier caractère n'est que pour le temps pour le temps imparti, la seconde indique le type de l'objet testé (C = Classe, F = fonction, I = Entier, S = String) et le reste indique la méthode (Attribut - Vérifier l'attribut, Appel - Utilisez appelable, essayez - utilisez TRY / SAUF). P>

tcattr 0.03665385400199739
tccall 0.026238360142997408
tctry 0.09736267629614304
tfattr 0.03624538065832894
tfcall 0.026362861895904643
tftry 0.032501874250556284
tiattr 0.08297350149314298
ticall 0.025826044152381655
titry 0.10657657453430147
tsattr 0.0840187013927789
tscall 0.02585409547373274
tstry 0.10742772077628615


1 commentaires

Sidenote: appelable était Supplégé dans Python3.0 et - après avoir remarqué que cette était un mauvais choix - rapporté à 3.2


3 Réponses :


4
votes

appelable n'est pas seulement le plus rapide, mais le zen fournit quatre raisons plus importantes de l'utiliser au lieu des deux autres contraptions:

belle est meilleure que laide.
Explicite vaut mieux que implicite.
Simple est meilleur que complexe.
Compte de lisibilité.


0 commentaires

6
votes

hasattr () retournera plus de faux positifs que appelable : xxx

Je ne suis pas sûr que appelable < / Code> Vous testiez, mais les deux ont l'air plus agréable que hasattr et gérer plus de cas, alors je les utiliserais à la place de hasattr () .


3 commentaires

appelable peut également revenir faux positifs .


@ J.f.sebastian - True, mais seule une personne folle définirait une classe avec un __ appelé __ __ . Ce serait juste un bogue en code réel.


Merci à vous deux pour la perspective. En complétude, j'utilisais l'appelable intégré, pas les collections.



4
votes

Grande question! Je dirais que vous devriez utiliser appelable . Plusieurs points à part le problème de la vitesse:

  1. C'est explicite, simple, claire, courte et soignée.
  2. C'est un python intégré, alors quiconque qui ne sait pas déjà ce qu'il peut trouver facilement.
  3. Essayez ... SAUF TypeError a un problème: TypeError peut parfois être soulevé par d'autres choses. Par exemple, si vous appelez avec succès une fonction qui soulève typeError dans son corps, le sauf va attraper à tort cela et supposer que l'objet n'était pas appelable.
  4. Certaines personnalisations courantes, telles que __ getattr __ , peuvent causer hasattr pour faire des erreurs.
  5. collections.abc.callable semble être plutôt lourdement lourd pour quelque chose de si simple. Après tout, appelable fait le même travail.

    Note de bas de page: The Essayez Block est un très courant Motif en Python pour ce genre de chose, vous pouvez donc en voir beaucoup dans le code des autres personnes. Cependant, comme je l'ai décrit ci-dessus, c'est un cas où il n'est pas tout à fait approprié.


0 commentaires