Wie erkenne ich, ob eine Variable eine Funktion ist?
Lesezeit: 11 Minuten
Daniel h
Ich habe eine Variable, xund ich möchte wissen, ob es auf eine Funktion zeigt 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
Der Grund, warum ich das ausgewählt habe, ist, weil
>>> type(x)
<type 'function'>
Ich bin deprimiert von der Anzahl der Antworten, die das Problem umgehen, indem ich nach einigen suche Anruf Attribut oder aufrufbare Funktion … Ein sauberer Weg geht über type(a) == types.functionType, wie von @ryan vorgeschlagen
– AsTeR
20. September 2013 um 12:09 Uhr
@ASter Der richtige Weg, um die Eigenschaften von Objekten vom 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. Der Ansatz “direkt vergleichen” gibt für viele Funktionen, wie z. B. integrierte Funktionen, die falsche Antwort.
– Johannes Feminella
2. Juni 2014 um 16:58 Uhr
@JohnFeminella Wobei ich dir prinzipiell zustimme. Das OP hat nicht gefragt, ob es aufrufbar ist, sondern nur, ob es sich um eine Funktion handelt. Vielleicht könnte man argumentieren, dass er zum Beispiel eine Unterscheidung zwischen Funktionen und Klassen brauchte?
– McKay
28. Februar 2017 um 18:15 Uhr
Für meine Zwecke bin ich hierher gekommen, weil ich es nutzen wollte insepct.getsource auf eine Vielzahl von Objekten, und es spielt eigentlich keine Rolle, ob das Objekt aufrufbar war, sondern ob es etwas war, das “Funktion” für geben würde type(obj). Da mich Google hierher geführt hat, würde ich sagen, dass der Kommentar von AsTeR die nützlichste Antwort war (für mich). Es gibt viele andere Orte im Internet, die die Leute entdecken können __call__ oder callable.
– Zbertalan
7. Dezember 2017 um 21:23 Uhr
@ASter Es ist types.FunctionType, mit einem großen F.
– Ben Stuten
8. November 2019 um 17:32 Uhr
Johannes Feminella
Wenn dies für Python 2.x oder für Python 3.2+ ist, können Sie verwenden callable(). Es war früher veraltet, ist aber jetzt nicht mehr veraltet, sodass Sie es wieder verwenden können. Die Diskussion können Sie hier nachlesen: http://bugs.python.org/issue10518. Sie können dies tun mit:
callable(obj)
Wenn dies für Python 3.x, aber vor 3.2 ist, überprüfen Sie, ob das Objekt eine hat __call__ Attribut. Sie können dies tun mit:
hasattr(obj, '__call__')
Das oft suggerierte types.FunctionTypes oder inspect.isfunction Ansatz (beide tun genau dasselbe) enthält eine Reihe von Einschränkungen. Es kehrt zurück False für Nicht-Python-Funktionen. Die meisten eingebaute Funktionensind beispielsweise in C und nicht in Python implementiert, daher kehren sie zurück False:
Also types.FunctionType könnte Ihnen überraschende Ergebnisse liefern. Der richtige Weg, die Eigenschaften von entenartigen Objekten zu überprüfen, besteht darin, sie zu fragen, ob sie quaken, und nicht, um zu sehen, ob sie in einen Behälter in Entengröße passen.
Dies sagt Ihnen auch nicht, ob es sich um eine Funktion handelt, sondern nur, ob sie aufgerufen werden kann.
– Chris B.
9. März 2009 um 4:02 Uhr
Hängt von der Anwendung ab, ob die Unterscheidung wichtig ist oder nicht; Ich vermute, Sie haben Recht, dass dies für die ursprüngliche Frage nicht gilt, aber das ist alles andere als sicher.
– Chris B.
9. März 2009 um 5:33 Uhr
Klassen können a Anruf damit verbundene Funktion. Dies ist also definitiv keine gute Methode zur Unterscheidung. Ryans Methode ist besser.
– Brian Brüggemann
2. Dezember 2011 um 20:12 Uhr
Das Konzept der “Ententypisierung” macht dies zur besseren Antwort, z. B. “Was spielt es für eine Rolle, ob es sich um eine Funktion handelt, solange sie sich wie eine verhält?”
– jcomeau_ictx
2. Januar 2012 um 4:02 Uhr
Es gibt Anwendungsfälle, in denen die Unterscheidung zwischen einem aufrufbaren und einer Funktion entscheidend ist, beispielsweise beim Schreiben eines Dekorateurs (siehe meinen Kommentar zu Ryans Antwort).
– Turi
6. Dezember 2013 um 22:26 Uhr
Ryan
Eingebaute Typen, die keine Konstruktoren im eingebauten Namensraum haben (z. B. Funktionen, Generatoren, Methoden), befinden sich in der types Modul. Sie können verwenden types.FunctionType in einem (n isinstance Anruf:
Beachten Sie, dass dies einen sehr spezifischen Begriff von “Funktion” verwendet, der normalerweise nicht das ist, was Sie brauchen. Sie lehnt zum Beispiel ab zip (technisch eine Klasse):
Wenn Sie etwas Bestimmtes tun types.FunctionType Instanzen, wie das Dekompilieren ihres Bytecodes oder das Untersuchen von Closure-Variablen, verwenden types.FunctionTypeaber wenn Sie nur ein Objekt benötigen, das wie eine Funktion aufgerufen werden kann, verwenden Sie callable.
+1 Beantwortung der Frage. Der Versuch zu erraten, ob ein Objekt eine Funktion ist – oder sogar ein aufrufbares Objekt – ist normalerweise ein Fehler. Ohne weitere Informationen vom OP ist es natürlich schwierig, es von der Hand zu weisen, aber trotzdem …
– Bobin
9. März 2009 um 4:49 Uhr
Es wird tatsächlich False für eingebaute Funktionen zurückgeben, wie ‘open’ für zB. Um genau zu sein, müssen Sie isinstance(f, (types.FunctionType, types.BuiltinFunctionType)) verwenden. Und natürlich, wenn Sie nur Funktionen wollen, keine Callables oder Methoden.
– Lukasz Korzybski
20. April 2011 um 14:06 Uhr
@ŁukaszKorzybski und um genauer zu sein … sollten Sie auch nach functools.partial suchen: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial)) oder prüfen f.func in einem solchen Fall.
– estani
17. Januar 2013 um 12:04 Uhr
@bobince, wie wäre es mit diesem Anwendungsfall: Ich möchte einen Dekorateur schreiben @foo dass ich beides als verwenden kann @foo und wie @foo(some_parameter). Es muss dann prüfen, womit es aufgerufen wird, zB die zu dekorierende Funktion (erster Fall) oder der Parameter (zweiter Fall, in dem es einen weiteren Dekorator zurückgeben muss).
– Turi
6. Dezember 2013 um 22:24 Uhr
types.BuiltinFunctionType ist auch der typ (“normal”) eingebaut Methodenwas Sie wahrscheinlich nicht zulassen möchten, wenn Sie nicht gehen callable Route.
Siehe die inspect.isfunction Dokumentstring: “Gib true zurück, wenn das Objekt eine benutzerdefinierte Funktion ist.”
– Mark Mikofski
6. August 2013 um 20:27 Uhr
Beachten Sie, dass „isfunction“ functool.partial-Funktionen nicht erkennt.
– Ismael
5. Dezember 2013 um 19:16 Uhr
Das gesamten Quellcode von isfunction ist return isinstance(object, types.FunctionType) es kommt also mit den Einschränkungen, auf die in @Ryans Antwort hingewiesen wird.
– Boris Werchowskij
23. Januar 2021 um 21:24 Uhr
SingleNegationElimination
Die akzeptierte Antwort wurde zum Zeitpunkt des Angebots für richtig gehalten. Wie sich herausstellt, gibt es das kein Ersatz zum callable()das wieder in Python 3.2 enthalten ist: Insbesondere callable() prüft die tp_call Feld des zu testenden Objekts. Es gibt kein einfaches Python-Äquivalent. Die meisten der vorgeschlagenen Tests sind meistens richtig:
Wir können einen Schraubenschlüssel hineinwerfen, indem wir die entfernen __call__ aus der Klasse. Und nur um die Dinge besonders spannend zu halten, fügen Sie eine Fälschung hinzu __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() gibt das richtige Ergebnis zurück:
>>> callable(can_o_spam)
False
Aber hasattr ist falsch:
>>> hasattr(can_o_spam, '__call__')
True
can_o_spam hat dieses Attribut doch; Es wird nur nicht verwendet, wenn die Instanz aufgerufen wird.
Noch subtiler, isinstance() versteh das auch falsch:
Da wir diese Überprüfung früher verwendet und die Methode später gelöscht haben, abc.ABCMeta
speichert das Ergebnis. Vermutlich handelt es sich hier um einen Bug-in abc.ABCMeta. Das heißt, es gibt wirklich keine Möglichkeit könnte produzieren ein genaueres Ergebnis als das Ergebnis als mit callable() selbst, da die typeobject->tp_call
Die Slot-Methode ist auf keine andere Weise zugänglich.
Benutz einfach callable()
Folgendes sollte einen booleschen Wert zurückgeben:
callable(x)
Das löst sein Problem, aber er hat immer noch ein Rätsel geschaffen: wenn x in Modul von der Klasse ‘Funktion’ ist eingebautund help(x.__class__) beschreibt “Klassenfunktion”, warum ist “Funktion” anscheinend “nicht definiert”?
– Ken
9. März 2009 um 3:52 Uhr
„Funktion“ ist kein Schlüsselwort oder ein eingebauter Typ. Der Funktionstyp wird im Modul “types” als “types.FunctionType” definiert.
Das löst sein Problem, aber er hat immer noch ein Rätsel geschaffen: wenn x in Modul von der Klasse ‘Funktion’ ist eingebautund help(x.__class__) beschreibt “Klassenfunktion”, warum ist “Funktion” anscheinend “nicht definiert”?
– Ken
9. März 2009 um 3:52 Uhr
„Funktion“ ist kein Schlüsselwort oder ein eingebauter Typ. Der Funktionstyp wird im Modul “types” als “types.FunctionType” definiert.
Ich bin deprimiert von der Anzahl der Antworten, die das Problem umgehen, indem ich nach einigen suche Anruf Attribut oder aufrufbare Funktion … Ein sauberer Weg geht über type(a) == types.functionType, wie von @ryan vorgeschlagen
– AsTeR
20. September 2013 um 12:09 Uhr
@ASter Der richtige Weg, um die Eigenschaften von Objekten vom 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. Der Ansatz “direkt vergleichen” gibt für viele Funktionen, wie z. B. integrierte Funktionen, die falsche Antwort.
– Johannes Feminella
2. Juni 2014 um 16:58 Uhr
@JohnFeminella Wobei ich dir prinzipiell zustimme. Das OP hat nicht gefragt, ob es aufrufbar ist, sondern nur, ob es sich um eine Funktion handelt. Vielleicht könnte man argumentieren, dass er zum Beispiel eine Unterscheidung zwischen Funktionen und Klassen brauchte?
– McKay
28. Februar 2017 um 18:15 Uhr
Für meine Zwecke bin ich hierher gekommen, weil ich es nutzen wollte
insepct.getsource
auf eine Vielzahl von Objekten, und es spielt eigentlich keine Rolle, ob das Objekt aufrufbar war, sondern ob es etwas war, das “Funktion” für geben würdetype(obj)
. Da mich Google hierher geführt hat, würde ich sagen, dass der Kommentar von AsTeR die nützlichste Antwort war (für mich). Es gibt viele andere Orte im Internet, die die Leute entdecken können__call__
odercallable
.– Zbertalan
7. Dezember 2017 um 21:23 Uhr
@ASter Es ist types.FunctionType, mit einem großen F.
– Ben Stuten
8. November 2019 um 17:32 Uhr