Question Comment détecter si une variable Python est une fonction?


J'ai une variable, x, et je veux savoir si elle pointe vers une fonction ou non.

J'avais espéré pouvoir faire quelque chose comme:

>>> isinstance(x, function)

Mais cela me donne:

Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'function' is not defined

La raison pour laquelle j'ai choisi cela est parce que

>>> type(x)
<type 'function'>

484
2018-03-09 03:31


origine


Réponses:


Si cela concerne Python 2.x ou Python 3.2+, vous pouvez également utiliser callable(). Auparavant, il était obsolète, mais il est maintenant obsolète, vous pouvez donc l'utiliser à nouveau. Vous pouvez lire la discussion ici: http://bugs.python.org/issue10518. Vous pouvez le faire avec:

callable(obj)

Si ceci est pour Python 3.x mais avant 3.2, vérifiez si l'objet a un __call__ attribut. Vous pouvez le faire avec:

hasattr(obj, '__call__')

Le souvent suggéré types.FunctionTypes L'approche n'est pas correcte car elle ne couvre pas beaucoup de cas que vous voudriez probablement voir passer, comme avec les commandes intégrées:

>>> isinstance(open, types.FunctionType)
False

>>> callable(open)
True

La bonne façon de vérifier les propriétés des objets de type canard est de leur demander s’ils plaisantent, et non de voir s’ils s’insèrent dans un conteneur de la taille d’un canard. Ne pas utiliser types.FunctionType sauf si vous avez une idée très précise de ce qu'est une fonction.


642
2018-03-09 03:39



Les types intégrés qui n’ont pas de constructeurs dans l’espace de noms intégré (par exemple, les fonctions, les générateurs, les méthodes) sont dans le types module. Vous pouvez utiliser types.FunctionType dans un appel isinstance.

In [1]: import types
In [2]: types.FunctionType
Out[2]: <type 'function'>
In [3]: def f(): pass
   ...:
In [4]: isinstance(f, types.FunctionType)
Out[4]: True
In [5]: isinstance(lambda x : None, types.FunctionType)
Out[5]: True

228
2018-03-09 03:47



Depuis Python 2.1 vous pouvez importer isfunction du inspect module.

>>> from inspect import isfunction
>>> def f(): pass
>>> isfunction(f)
True
>>> isfunction(lambda x: x)
True

77
2017-11-28 21:40



La réponse acceptée était au moment où il a été offert pensé pour être correct. Comme ca s'avère, il y a pas de substitut pour callable(), qui est de retour en Python 3.2: Plus précisément, callable() vérifie la tp_call champ de l'objet étant testé. Il n'y a pas d'équivalent en Python. La plupart des tests suggérés sont corriger la plupart du temps:

>>> class Spam(object):
...     def __call__(self):
...         return 'OK'
>>> can_o_spam = Spam()


>>> can_o_spam()
'OK'
>>> callable(can_o_spam)
True
>>> hasattr(can_o_spam, '__call__')
True
>>> import collections
>>> isinstance(can_o_spam, collections.Callable)
True

Nous pouvons lancer une clé de singe en supprimant le __call__ du classe. Et juste pour garder les choses plus excitantes, ajouter un faux __call__ à l'instance!

>>> del Spam.__call__
>>> can_o_spam.__call__ = lambda *args: 'OK?'

Notez que ceci n'est vraiment pas appelable:

>>> can_o_spam()
Traceback (most recent call last):
  ...
TypeError: 'Spam' object is not callable

callable() renvoie le résultat correct:

>>> callable(can_o_spam)
False

Mais hasattr est faux:

>>> hasattr(can_o_spam, '__call__')
True

can_o_spam a cet attribut après tout; il est juste pas utilisé lors de l'appel l'instance.

Encore plus subtile, isinstance() aussi se trompe:

>>> isinstance(can_o_spam, collections.Callable)
True

Parce que nous avons utilisé cette vérification plus tôt et plus tard supprimé la méthode, abc.ABCMeta met en cache le résultat. Sans doute c'est un bug dans abc.ABCMeta. Cela dit, il n'y a vraiment pas de moyen possible pourrait produire un résultat plus précis que le résultat qu'en utilisant callable() lui-même, depuis le typeobject->tp_call la méthode des emplacements n’est pas accessible d’une autre manière.

Juste utiliser callable()


48
2017-09-09 18:42



Ce qui suit devrait renvoyer un booléen:

callable(x)

31
2018-03-09 03:33



Outil 2to3 de Python (http://docs.python.org/dev/library/2to3.html) suggère:

import collections
isinstance(obj, collections.Callable)

Il semble que cela a été choisi au lieu de la hasattr(x, '__call__') méthode en raison de http://bugs.python.org/issue7006.


21
2017-11-20 18:27



callable(x)  volonté renvoie true si l'objet passé peut être appelé en Python, mais la fonction n'existe pas dans Python 3.0 et ne fera pas de distinction entre:

class A(object):
    def __call__(self):
        return 'Foo'

def B():
    return 'Bar'

a = A()
b = B

print type(a), callable(a)
print type(b), callable(b)

Tu auras <class 'A'> True et <type function> Trueen sortie.

isinstance fonctionne parfaitement pour déterminer si quelque chose est une fonction (essayez isinstance(b, types.FunctionType)) Si vous êtes vraiment intéressé à savoir si quelque chose peut être appelé, vous pouvez soit utiliser hasattr(b, '__call__') ou essayez-le.

test_as_func = True
try:
    b()
except TypeError:
    test_as_func = False
except:
    pass

Cela, bien sûr, ne vous dira pas si elle est appelable mais jette un TypeError quand il s'exécute, ou n'est pas appelable en premier lieu. Cela peut ne pas vous intéresser.


17
2018-03-09 03:58



Si vous voulez détecter tout ce qui ressemble syntaxiquement à une fonction: une fonction, une méthode, une fonction intégrée fun / meth, lambda ... mais exclure objets appelables (objets avec __call__ méthode définie), puis essayez celle-ci:

import types
isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))

J'ai comparé cela avec le code de is*() les contrôles inspect module et l'expression ci-dessus est beaucoup plus complète, surtout si votre objectif est de filtrer toutes les fonctions ou de détecter les propriétés régulières d'un objet.


9
2017-11-28 12:42