971 Stimmen

Wie kann ich feststellen, ob eine Python-Variable eine Funktion ist?

Ich habe eine Variable, x und ich möchte wissen, ob sie auf eine Funktion verweist oder nicht.

Ich hatte gehofft, ich könnte so etwas tun:

>>> isinstance(x, function)

Aber das gibt mir:

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

Ich habe das deshalb gewählt, weil

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

61 Stimmen

Ich bin deprimiert über die Anzahl der Antworten, die das Problem umgehen, indem sie nach einigen aufrufen Attribut oder aufrufbare Funktion... Ein sauberer Weg ist über type(a) == types.functionType wie von @ryan vorgeschlagen

65 Stimmen

@AsTeR Die richtige Art und Weise, die Eigenschaften von Objekten mit dem Typ "Ente" zu prüfen, besteht darin, sie zu fragen, ob sie quaken, und nicht zu sehen, ob sie in einen Behälter in Entengröße passen. Der Ansatz "direkt vergleichen" wird für viele Funktionen, wie z.B. Builtins, die falsche Antwort geben.

5 Stimmen

@JohnFeminella Ich stimme Ihnen zwar im Prinzip zu. Der OP hat nicht gefragt, ob es aufrufbar ist, sondern nur, ob es eine Funktion ist. Vielleicht könnte man argumentieren, dass er eine Unterscheidung zwischen z.B. Funktionen und Klassen benötigt?

1226voto

John Feminella Punkte 292907

Wenn dies für Python 2.x oder für Python 3.2+ ist, können Sie callable() . Früher war es veraltet, aber jetzt ist es nicht mehr veraltet, so dass Sie es wieder verwenden können. Sie können die Diskussion hier lesen: http://bugs.python.org/issue10518 . Sie können dies mit tun:

callable(obj)

Wenn dies für Python 3.x aber vor 3.2 ist, prüfen Sie, ob das Objekt eine __call__ Attribut. Sie können dies mit tun:

hasattr(obj, '__call__')

Die oft vorgeschlagene types.FunctionTypes o inspect.isfunction Ansatz (beide tun genau das Gleiche ) ist mit einer Reihe von Vorbehalten behaftet. Sie liefert False für Nicht-Python-Funktionen. Die meisten eingebaute Funktionen zum Beispiel sind in C und nicht in Python implementiert und geben daher False :

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

also types.FunctionType könnten Sie überraschende Ergebnisse erzielen. Die richtige Art und Weise, die Eigenschaften von Objekten mit dem Typ "Ente" zu überprüfen, besteht darin, sie zu fragen, ob sie quaken, und nicht zu sehen, ob sie in einen Behälter in Entengröße passen.

111 Stimmen

Dies sagt Ihnen auch nicht, ob es sich um eine Funktion handelt, sondern nur, ob sie aufgerufen werden kann.

30 Stimmen

Es hängt von der Anwendung ab, ob die Unterscheidung von Bedeutung ist oder nicht; ich vermute, dass Sie Recht haben, dass sie für die ursprüngliche Frage nicht von Bedeutung ist, aber das ist alles andere als sicher.

10 Stimmen

Klassen können eine aufrufen Funktion zugewiesen. Dies ist also definitiv keine gute Methode zur Unterscheidung. Die Methode von Ryan ist besser.

346voto

Ryan Punkte 14482

Eingebaute Typen, die keine Konstruktoren im eingebauten Namensraum haben (z. B. Funktionen, Generatoren, Methoden), befinden sich im types Modul. Sie können das types.FunctionType in einem isinstance anrufen:

>>> import types
>>> types.FunctionType
<class 'function'>

>>> def f(): pass

>>> isinstance(f, types.FunctionType)
True
>>> isinstance(lambda x : None, types.FunctionType)
True

Beachten Sie, dass hier ein sehr spezifischer Begriff von "Funktion" verwendet wird, der in der Regel nicht das ist, was Sie brauchen. Es lehnt zum Beispiel ab zip (technisch gesehen eine Klasse):

>>> type(zip), isinstance(zip, types.FunctionType)
(<class 'type'>, False)

open (eingebaute Funktionen haben einen anderen Typ):

>>> type(open), isinstance(open, types.FunctionType)
(<class 'builtin_function_or_method'>, False)

y random.shuffle (technisch eine Methode eines versteckten random.Random Instanz):

>>> type(random.shuffle), isinstance(random.shuffle, types.FunctionType)
(<class 'method'>, False)

Wenn Sie etwas Bestimmtes tun, um types.FunctionType Instanzen, wie z. B. die Dekompilierung ihres Bytecodes oder die Untersuchung von Schließungsvariablen, verwenden types.FunctionType aber wenn Sie nur ein Objekt brauchen, das wie eine Funktion aufgerufen werden kann, verwenden Sie callable .

7 Stimmen

+1 Beantwortung der Frage. Der Versuch, zu erraten, ob es sich bei einem Objekt um eine Funktion handelt - oder ob es überhaupt ein aufrufbares Objekt ist - ist jedoch in der Regel ein Fehler. Ohne weitere Informationen des Auftraggebers ist es natürlich schwierig, die Frage von vornherein abzulehnen, aber dennoch...

52 Stimmen

Für Builtin-Funktionen, wie z. B. 'open', wird False zurückgegeben. Um genau zu sein, müssen Sie also isinstance(f, (types.FunctionType, types.BuiltinFunctionType)) verwenden. Und natürlich, wenn Sie unbedingt nur Funktionen, nicht Callables oder Methoden wollen.

6 Stimmen

@ukaszKorzybski und um noch genauer zu sein... Sie sollten auch functools.partial überprüfen: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial)) oder Prüfung f.func in einem solchen Fall.

109voto

Paolo Punkte 17469

Seit Python 2.1 können Sie importieren isfunction von der inspect Modul.

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

4 Stimmen

Nett, aber es scheint False zurückzugeben für eingebaute Funktionen wie open y hasattr .

14 Stimmen

@Zecc isbuiltin ist dafür.

15 Stimmen

Siehe die inspect.isfunction docstring: "Gibt true zurück, wenn das Objekt eine benutzerdefinierte Funktion ist."

88voto

Die akzeptierte Antwort wurde zu dem Zeitpunkt, als sie angeboten wurde, für richtig gehalten. Wie sich stellt sich heraus, dass es eine kein Ersatz para callable() die wieder in Python enthalten ist 3.2: Genauer gesagt, callable() prüft die tp_call Feld des Objekts, das getestet wird. Es gibt keine einfache Python-Entsprechung. Die meisten der vorgeschlagenen Tests sind die meiste Zeit über korrekt:

>>> 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

Wir können dem Ganzen einen Strich durch die Rechnung machen, indem wir die __call__ aus der Klasse. Und um die Sache noch spannender zu machen, fügen Sie eine gefälschte __call__ zur Instanz!

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

Beachten Sie, dass dies wirklich nicht aufrufbar ist:

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

callable() liefert das richtige Ergebnis:

>>> callable(can_o_spam)
False

Aber hasattr es falsch :

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

can_o_spam hat dieses Attribut doch; es wird nur nicht verwendet, wenn die der Instanz.

Noch subtiler, isinstance() ist auch hier falsch:

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

Denn wir haben diese Prüfung früher verwendet und die Methode später gelöscht, abc.ABCMeta zwischenspeichert das Ergebnis. Dies ist wohl ein Fehler in abc.ABCMeta . Das heißt, gibt es wirklich keine Möglichkeit, dass es könnte ein genaueres Ergebnis liefern als das Ergebnis als bei der Verwendung von callable() selbst, da die typeobject->tp_call Die Slot-Methode ist auf keine andere Weise zugänglich.

Verwenden Sie einfach callable()

7 Stimmen

Erstaunliches Beispiel für die Fallstricke der hasattr(o, '__call__') Ansatz und warum callable() falls vorhanden, besser ist.

54voto

Nikhil Punkte 5607

Das folgende sollte einen booleschen Wert zurückgeben:

callable(x)

1 Stimmen

Damit ist sein Problem gelöst, aber er hat immer noch ein Rätsel geschaffen: Wenn x von der Klasse 'Funktion' im Modul eingebautes , und help(x.__class__) beschreibt "class function", warum ist "function" offenbar "not defined"?

2 Stimmen

"Funktion" ist weder ein Schlüsselwort noch ein eingebauter Typ. Der Typ von Funktionen ist im Modul "types" definiert, als "types.FunctionType".

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X