Come posso rilevare se una variabile Python è una funzione?


688

Ho una variabile xe voglio sapere se punta a una funzione o meno.

Speravo di poter fare qualcosa del tipo:

>>> isinstance(x, function)

Ma questo mi dà:

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

Il motivo per cui l'ho scelto è perché

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

37
Sono depresso dal numero di risposte che aggirano il problema cercando un attributo di chiamata o una funzione richiamabile ... Un modo chiaro è di tipo (a) == types.functionTipo come suggerito da @ryan
AsTeR

44
@AsTeR Il modo corretto di controllare le proprietà degli oggetti digitati su anatre è chiedere loro se ciondolano, non per vedere se si adattano in un contenitore delle dimensioni di un'anatra. L'approccio "confronta direttamente" darà la risposta sbagliata per molte funzioni, come i builtin.
John Feminella,

3
@JohnFeminella Mentre sono d'accordo con te in linea di principio. L'OP non ha chiesto se fosse richiamabile, solo se è una funzione. Forse si potrebbe sostenere che aveva bisogno di una distinzione tra, ad esempio, funzioni e classi?
McKay,

3
Per i miei scopi, sono venuto qui perché volevo usare insepct.getsourcesu una varietà di oggetti, e in realtà non importa se l'oggetto fosse richiamabile, ma se fosse qualcosa che avrebbe dato 'funzione' type(obj). Dato che Google mi ha portato qui, direi che il commento di AsTeR è stata la risposta più utile (per me). Ci sono molti altri posti su Internet che le persone possono scoprire __call__o callable.
Tsbertalan,

4
@AsTeR È types.FunctionType, con la maiuscola F.
Ben Mares

Risposte:


893

Se questo è per Python 2.xo per Python 3.2+, puoi anche usare callable(). Prima era obsoleto, ma ora non è più indicato, quindi puoi usarlo di nuovo. Puoi leggere la discussione qui: http://bugs.python.org/issue10518 . Puoi farlo con:

callable(obj)

Se questo è per Python 3.x ma prima della 3.2, controlla se l'oggetto ha un __call__attributo. Puoi farlo con:

hasattr(obj, '__call__')

L' types.FunctionTypesapproccio spesso suggerito non è corretto perché non copre molti casi che presumibilmente vorresti che passasse, come con builtin:

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

>>> callable(open)
True

Il modo corretto di controllare le proprietà degli oggetti digitati su anatre è chiedere loro se cigolano, per non vedere se si adattano in un contenitore delle dimensioni di un'anatra. Non usare a types.FunctionTypemeno che tu non abbia un'idea molto specifica di cosa sia una funzione.


73
Anche questo non ti dirà se è una funzione, solo se può essere chiamata.
Chris B.

23
Dipende dall'applicazione indipendentemente dal fatto che la distinzione contenga o meno; Ho il sospetto che tu abbia ragione nel dire che non è per la domanda originale, ma non è certo.
Chris B.

5
Alle classi può essere associata una funzione di chiamata . Quindi questo non è sicuramente un buon metodo per distinguere. Il metodo di Ryan è migliore.
Brian Bruggeman,

43
il concetto di "tipizzazione anatra" rende questa la risposta migliore, ad esempio "che importanza ha se è una funzione fintanto che si comporta come una?"
jcomeau_ictx il

8
Ci sono casi d'uso in cui la distinzione tra un callable e una funzione è cruciale, ad esempio quando si scrive un decoratore (vedere il mio commento sulla risposta di Ryan).
Turion,

266

I tipi incorporati che non hanno costruttori nello spazio dei nomi incorporato (ad es. Funzioni, generatori, metodi) sono nel typesmodulo. È possibile utilizzare types.FunctionTypein una isinstancechiamata:

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

Nota che questo usa una nozione molto specifica di "funzione" che di solito non è ciò di cui hai bisogno. Ad esempio, rifiuta zip(tecnicamente una classe):

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

open (le funzioni integrate hanno un tipo diverso):

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

e random.shuffle(tecnicamente un metodo di random.Randomun'istanza nascosta ):

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

Se stai facendo qualcosa di specifico per le types.FunctionTypeistanze, come decompilare il loro bytecode o ispezionare le variabili di chiusura, usa types.FunctionType, ma se hai solo bisogno di un oggetto per essere richiamabile come una funzione, usa callable.


5
+1 rispondendo alla domanda. Tuttavia, provare a indovinare se un oggetto è una funzione - o anche se si tratta di un oggetto richiamabile - di solito è un errore. Senza ulteriori informazioni dall'OP è difficile respingerlo ovviamente, ma comunque ...
bobince

47
Restituirà effettivamente False per le funzioni integrate, come 'open' per es. Quindi per essere specifici dovrai usare isinstance (f, (types.FunctionType, types.BuiltinFunctionType)). E ovviamente se vuoi solo funzioni, non callable né metodi.
Lukasz Korzybski,

5
@ ŁukaszKorzybski e per essere più precisi ... dovresti anche controllare functools.partial: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial))o fare il check- f.funcin in questo caso.
estani,

3
@bobince, che ne dici di questo caso d'uso: voglio scrivere un decoratore @fooche posso usare sia come @fooche come @foo(some_parameter). Deve quindi controllare con cosa viene chiamato, ad esempio la funzione per decorare (primo caso) o il parametro (il secondo caso, in cui deve restituire un ulteriore decoratore).
Turion,

types.BuiltinFunctionTypeè anche il tipo di metodi ("normali") incorporati , che probabilmente non vuoi consentire, se non stai seguendo il callablepercorso.
user2357112 supporta Monica il

92

Da Python 2.1 è possibile importare isfunctiondal inspectmodulo.

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

3
Bello, ma sembra restituire False per funzioni integrate come opene hasattr.
Zecc,

12
@Zecc isbuiltin è per questo.
Paolo,

13
Vedi il inspect.isfunctiondocstring: "Restituisce vero se l'oggetto è una funzione definita dall'utente."
Mark Mikofski,

4
Notare che 'isfunction' non riconosce le funzioni functool.partial.
Ismaele

74

La risposta accettata era nel momento in cui veniva offerta ritenuta corretta. Come si è visto, non v'è alcun sostituto per callable(), che è di nuovo in Python 3.2: In particolare, callable()controlla il tp_callcampo dell'oggetto in fase di test. Non esiste un semplice equivalente Python. La maggior parte dei test suggeriti sono corretti il ​​più delle volte:

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

Possiamo buttarci dentro una chiave inglese togliendola __call__dalla classe. E solo per rendere le cose ancora più emozionanti, aggiungi un falso __call__all'istanza!

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

Si noti che questo non è davvero richiamabile:

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

callable() restituisce il risultato corretto:

>>> callable(can_o_spam)
False

Ma hasattrè sbagliato :

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

can_o_spamdopo tutto ha quell'attributo; non viene utilizzato quando si chiama l'istanza.

Ancora più sottile, isinstance()sbaglia anche questo:

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

Poiché abbiamo utilizzato questo controllo prima e successivamente eliminato il metodo, abc.ABCMeta memorizza nella cache il risultato. Probabilmente questo è un bug in abc.ABCMeta. Detto questo, non c'è davvero alcun modo in cui possa produrre un risultato più accurato del risultato se non usando callable()se stesso, dal momento chetypeobject->tp_call metodo di slot non è accessibile in nessun altro modo.

Basta usare callable()


5
Incredibile illustrazione delle insidie ​​di hasattr(o, '__call__') dell'approccio e perché callable(), se disponibile, è superiore.
MestreLion,

39

Quanto segue dovrebbe restituire un valore booleano:

callable(x)

1
Ciò risolve il suo problema, ma ha comunque creato un mistero: se x è di "funzione" di classe nel modulo incorporato e help (x .__ class__) descrive "funzione di classe", perché "funzione" apparentemente "non è definita"?
Ken

1
"funzione" non è una parola chiave o un tipo incorporato. Il tipo di funzioni è definito nel modulo "types", come "types.FunctionType"
Chris B.


19

callable(x) sarà Restituisce vero se l'oggetto passato può essere chiamato in Python, ma la funzione non esiste in Python 3.0, e propriamente non distinguere tra:

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)

Otterrai <class 'A'> Truee<type function> True come output.

isinstancefunziona perfettamente per determinare se qualcosa è una funzione (provare isinstance(b, types.FunctionType)); se sei veramente interessato a sapere se qualcosa può essere chiamato, puoi usarlo hasattr(b, '__call__')o semplicemente provarlo.

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

Questo, ovviamente, non ti dirà se è richiamabile ma genera un TypeErrorquando viene eseguito o non è richiamabile in primo luogo. Questo potrebbe non importarti.


8
Chiamarlo è una cattiva idea. Che cosa succede se ha effetti collaterali o effettivamente fa qualcosa ma richiede davvero molto tempo?
asmeurer,

@asmeurer - Perché altrimenti dovresti sapere se è una funzione se non la chiami?
Detly

1
@detly: per il debug voglio stampare regolarmente tutte le variabili in un oggetto, i metodi di solito non mi sono utili quindi non vorrei eseguirle. Alla fine ho appena elencato tutte le proprietà non richiamabili con i valori corrispondenti :)
Wolph

2
Solo perché non stai chiamando non significa che non viene chiamato. Forse stai spedendo.
asmeurer,

4
C'è un grosso problema con l'utilizzo delle eccezioni per sapere se era richiamabile o meno; cosa succede se è richiamabile, ma chiamarlo solleva un'eccezione che stai cercando? Entrambi ignorerai silenziosamente un errore e diagnosticherai erroneamente se era richiamabile. Quando usi EAFP, vuoi davvero evitare di provare troppo, ma non c'è modo di farlo per questo caso d'uso.
Ben

15

Se vuoi rilevare tutto ciò che sintatticamente assomiglia a una funzione: una funzione, un metodo, divertimento / meth incorporato, lambda ... ma escludi oggetti richiamabili (oggetti con __call__metodo definito), prova questo:

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

Ho confrontato questo con il codice dei is*()controlli nel inspectmodulo e l'espressione sopra è molto più completa, specialmente se il tuo obiettivo è filtrare qualsiasi funzione o rilevare proprietà regolari di un oggetto.


Grazie per avermi indicato il typesmodulo. Stavo testando una make_stemmer()fabbrica che a volte restituiva una funzione e talvolta Stemmerun'istanza richiamabile , e avevo bisogno di rilevare la differenza.
Piani cottura


6

Se hai imparato C++, devi conoscere function objecto functor, significa qualsiasi oggetto che puòbe called as if it is a function .

In C ++, an ordinary functionè un oggetto funzione, così come un puntatore a funzione; più in generale, quindi è un oggetto di una classe che definisce operator(). In C ++ 11 e versioni successive, the lambda expressionè ilfunctor troppo.

Somiglianza, in Python, quelli functorssono tutti callable. An ordinary functionpuò essere richiamabile, a lambda expressionpuò essere richiamabile, a functional.partialpuò essere richiamabile, le istanze di class with a __call__() methodpossono essere richiamabili.


Ok, torna alla domanda: I have a variable, x, and I want to know whether it is pointing to a function or not.

Se vuoi giudicare il tempo l'oggetto agisce come una funzione, quindi il callablemetodo suggerito da@John Feminella è ok.

Se si desidera judge whether a object is just an ordinary function or not(non un'istanza di classe richiamabile o un'espressione lambda), la xtypes.XXXproposta suggerita da @Ryanè una scelta migliore.

Quindi faccio un esperimento usando quel codice:

#!/usr/bin/python3
# 2017.12.10 14:25:01 CST
# 2017.12.10 15:54:19 CST

import functools
import types
import pprint

Definire una classe e una funzione ordinaria.

class A():
    def __call__(self, a,b):
        print(a,b)
    def func1(self, a, b):
        print("[classfunction]:", a, b)
    @classmethod
    def func2(cls, a,b):
        print("[classmethod]:", a, b)
    @staticmethod
    def func3(a,b):
        print("[staticmethod]:", a, b)

def func(a,b):
    print("[function]", a,b)

Definire i funzioni:

#(1.1) built-in function
builtins_func = open
#(1.2) ordinary function
ordinary_func = func
#(1.3) lambda expression
lambda_func  = lambda a : func(a,4)
#(1.4) functools.partial
partial_func = functools.partial(func, b=4)

#(2.1) callable class instance
class_callable_instance = A()
#(2.2) ordinary class function
class_ordinary_func = A.func1
#(2.3) bound class method
class_bound_method = A.func2
#(2.4) static class method
class_static_func = A.func3

Definisci l'elenco dei funzioni e l'elenco dei tipi:

## list of functors
xfuncs = [builtins_func, ordinary_func, lambda_func, partial_func, class_callable_instance, class_ordinary_func, class_bound_method, class_static_func]
## list of type
xtypes = [types.BuiltinFunctionType, types.FunctionType, types.MethodType, types.LambdaType, functools.partial]

Giudica se il funzione è richiamabile. Come puoi vedere, sono tutti richiamabili.

res = [callable(xfunc)  for xfunc in xfuncs]
print("functors callable:")
print(res)

"""
functors callable:
[True, True, True, True, True, True, True, True]
"""

Giudicare il tipo di funzione (types.XXX). Quindi i tipi di funzioni non sono tutti uguali.

res = [[isinstance(xfunc, xtype) for xtype in xtypes] for xfunc in xfuncs]

## output the result
print("functors' types")
for (row, xfunc) in zip(res, xfuncs):
    print(row, xfunc)

"""
functors' types
[True, False, False, False, False] <built-in function open>
[False, True, False, True, False] <function func at 0x7f1b5203e048>
[False, True, False, True, False] <function <lambda> at 0x7f1b5081fd08>
[False, False, False, False, True] functools.partial(<function func at 0x7f1b5203e048>, b=4)
[False, False, False, False, False] <__main__.A object at 0x7f1b50870cc0>
[False, True, False, True, False] <function A.func1 at 0x7f1b5081fb70>
[False, False, True, False, False] <bound method A.func2 of <class '__main__.A'>>
[False, True, False, True, False] <function A.func3 at 0x7f1b5081fc80>
"""

Traccio una tabella dei tipi di funzioni richiamabili usando i dati.

inserisci qui la descrizione dell'immagine

Quindi è possibile scegliere i tipi di funzione adatti.

ad esempio:

def func(a,b):
    print("[function]", a,b)

>>> callable(func)
True
>>> isinstance(func,  types.FunctionType)
True
>>> isinstance(func, (types.BuiltinFunctionType, types.FunctionType, functools.partial))
True
>>> 
>>> isinstance(func, (types.MethodType, functools.partial))
False

6

Come risposta accettata, John Feminella affermò che:

Il modo corretto di controllare le proprietà degli oggetti tipizzati con l'anatra è chiedere loro se cigolano, per non vedere se si adattano in un contenitore delle dimensioni di un'anatra. L'approccio "confronta direttamente" darà la risposta sbagliata per molte funzioni, come i builtin.

Anche se ci sono due librerie per distinguere rigorosamente le funzioni, disegno una tabella comparativa esaustiva:

8.9. tipi: creazione di nomi dinamici e nomi per tipi incorporati: documentazione di Python 3.7.0

30.13. inspect - Ispeziona oggetti live - Documentazione di Python 3.7.0

#import inspect             #import types
['isabstract',
 'isasyncgen',              'AsyncGeneratorType',
 'isasyncgenfunction', 
 'isawaitable',
 'isbuiltin',               'BuiltinFunctionType',
                            'BuiltinMethodType',
 'isclass',
 'iscode',                  'CodeType',
 'iscoroutine',             'CoroutineType',
 'iscoroutinefunction',
 'isdatadescriptor',
 'isframe',                 'FrameType',
 'isfunction',              'FunctionType',
                            'LambdaType',
                            'MethodType',
 'isgenerator',             'GeneratorType',
 'isgeneratorfunction',
 'ismethod',
 'ismethoddescriptor',
 'ismodule',                'ModuleType',        
 'isroutine',            
 'istraceback',             'TracebackType'
                            'MappingProxyType',
]

La "tipizzazione anatra" è una soluzione preferita per scopi generali:

def detect_function(obj):
    return hasattr(obj,"__call__")

In [26]: detect_function(detect_function)
Out[26]: True
In [27]: callable(detect_function)
Out[27]: True

Per quanto riguarda la funzione integrata

In [43]: callable(hasattr)
Out[43]: True

Quando fai un altro passo per verificare se la funzione integrata o la funzione definita dall'utente

#check inspect.isfunction and type.FunctionType
In [46]: inspect.isfunction(detect_function)
Out[46]: True
In [47]: inspect.isfunction(hasattr)
Out[47]: False
In [48]: isinstance(detect_function, types.FunctionType)
Out[48]: True
In [49]: isinstance(getattr, types.FunctionType)
Out[49]: False
#so they both just applied to judge the user-definded

Determina se builtin function

In [50]: isinstance(getattr, types.BuiltinFunctionType)
Out[50]: True
In [51]: isinstance(detect_function, types.BuiltinFunctionType)
Out[51]: False

Sommario

Impiegare callableper evitare il controllo del tipo di funzione,
utilizzare types.BuiltinFunctionTypese si dispone di ulteriori richieste specificate.


5

Una funzione è solo una classe con un __call__metodo, quindi puoi farlo

hasattr(obj, '__call__')

Per esempio:

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

>>> x = 2
>>> hasattr(x, '__call__')
False

Questo è il modo "migliore" per farlo, ma a seconda del motivo per cui è necessario sapere se è richiamabile o nota, è possibile inserirlo in un blocco try / execpt:

try:
    x()
except TypeError:
    print "was not callable"

È discutibile se provare / tranne è più Python che farlo if hasattr(x, '__call__'): x().. Direi che hasattrè più preciso, dal momento che non prenderai accidentalmente l'errore TypeError sbagliato, ad esempio:

>>> def x():
...     raise TypeError
... 
>>> hasattr(x, '__call__')
True # Correct
>>> try:
...     x()
... except TypeError:
...     print "x was not callable"
... 
x was not callable # Wrong!

Usa la gestione delle eccezioni per proteggere solo da comportamenti imprevisti, mai per il flusso logico, che sicuramente non è Pythonic.
gotgenes

Bene, hasattr fondamentalmente fa un getattr in un blocco try / tranne (anche se in C). blog.jancewicz.net/2007/10/reflection-hasattr.html
dbr

@dbr: hasattr è più estetico.
Nikhil Chelliah,

5

Ecco un paio di altri modi:

def isFunction1(f) :
    return type(f) == type(lambda x: x);

def isFunction2(f) :
    return 'function' in str(type(f));

Ecco come sono arrivato al secondo:

>>> type(lambda x: x);
<type 'function'>
>>> str(type(lambda x: x));
"<type 'function'>"
# Look Maa, function! ... I ACTUALLY told my mom about this!

Questo è carino! Dovrebbe funzionare su tutte le versioni di python2.xe python3.x!
Saurav Kumar

4

Invece di controllare per la '__call__'(che non è esclusivo per le funzioni), è possibile controllare se una funzione definita dall'utente ha attributi func_name, func_docecc Questo non funziona per i metodi.

>>> def x(): pass
... 
>>> hasattr(x, 'func_name')
True

Un altro modo di verificare è utilizzare il isfunction()metodo dal inspectmodulo.

>>> import inspect
>>> inspect.isfunction(x)
True

Per verificare se un oggetto è un metodo, utilizzare inspect.ismethod()


4

Poiché anche le classi hanno un __call__metodo, raccomando un'altra soluzione:

class A(object):
    def __init__(self):
        pass
    def __call__(self):
        print 'I am a Class'

MyClass = A()

def foo():
    pass

print hasattr(foo.__class__, 'func_name') # Returns True
print hasattr(A.__class__, 'func_name')   # Returns False as expected

print hasattr(foo, '__call__') # Returns True
print hasattr(A, '__call__')   # (!) Returns True while it is not a function

1
d'accordo con la tua risposta, la risposta di John Feminella hasattr(obj, '__call__')è ambigua.
GoingMyWay,

4

Nota che anche le classi Python sono richiamabili.

Per ottenere funzioni (e per funzioni intendiamo funzioni standard e lambdas) usare:

import types

def is_func(obj):
    return isinstance(obj, (types.FunctionType, types.LambdaType))


def f(x):
    return x


assert is_func(f)
assert is_func(lambda x: x)

2

Qualunque funzione sia una classe in modo da poter prendere il nome della classe dell'istanza x e confrontare:


if(x.__class__.__name__ == 'function'):
     print "it's a function"

2

Le soluzioni che utilizzano hasattr(obj, '__call__')e callable(.)menzionate in alcune delle risposte presentano un inconveniente principale: entrambi restituiscono anche Trueper le classi e le istanze delle classi con un __call__()metodo. Per esempio.

>>> import collections
>>> Test = collections.namedtuple('Test', [])
>>> callable(Test)
True
>>> hasattr(Test, '__call__')
True

Un modo corretto di verificare se un oggetto è una funzione definita dall'utente (e nient'altro che quello) è di usare isfunction(.):

>>> import inspect
>>> inspect.isfunction(Test)
False
>>> def t(): pass
>>> inspect.isfunction(t)
True

Se devi controllare altri tipi, dai un'occhiata a Ispeziona - Ispeziona oggetti vivi .


2

Un controllo funzione esatto

callable è un'ottima soluzione. Tuttavia, volevo trattare questo nel modo opposto di John Feminella. Invece di trattarlo in questo modo dicendo:

Il modo corretto di controllare le proprietà degli oggetti tipizzati con l'anatra è chiedere loro se cigolano, per non vedere se si adattano in un contenitore delle dimensioni di un'anatra. L'approccio "confronta direttamente" darà la risposta sbagliata per molte funzioni, come i builtin.

Lo tratteremo così:

Il modo corretto per verificare se qualcosa è un'anatra non è vedere se può ciarlare, ma piuttosto vedere se è davvero un'anatra attraverso diversi filtri, invece di verificare se sembra un'anatra dalla superficie.

Come lo implementeremmo

Il modulo 'types' ha molte classi per rilevare le funzioni, le più utili sono types.FunctionType , ma ce ne sono anche molte altre, come un tipo di metodo, un tipo incorporato e un tipo lambda. Considereremo anche un oggetto 'functools.partial' come una funzione.

Il modo semplice per verificare se si tratta di una funzione è utilizzando una condizione isinstance su tutti questi tipi. In precedenza, volevo creare una classe base che eredita da tutto quanto sopra, ma non sono in grado di farlo, poiché Python non ci consente di ereditare da alcune delle classi precedenti.

Ecco una tabella di quali classi possono classificare quali funzioni:

Tabella delle funzioni da kinght- 金 Sopra la tabella delle funzioni di kinght- 金

Il codice che lo fa

Ora, questo è il codice che fa tutto il lavoro che abbiamo descritto sopra.

from types import BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType
from functools import partial

def is_function(obj):
  return isinstance(obj, (BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType, partial))

#-------------------------------------------------

def my_func():
  pass

def add_both(x, y):
  return x + y

class a:
  def b(self):
    pass

check = [

is_function(lambda x: x + x),
is_function(my_func),
is_function(a.b),
is_function(partial),
is_function(partial(add_both, 2))

]

print(check)
>>> [True, True, True, False, True]

L'unico falso era is_function (parziale), perché quella è una classe, non una funzione, e questa è esattamente funzioni, non classi. Ecco un'anteprima per provare il codice.

Conclusione

callable (obj) è il metodo preferito per verificare se un oggetto è una funzione se si desidera passare digitando l'anatra sugli assoluti .

La nostra funzione personalizzata is_function (obj) , forse con alcune modifiche è il metodo preferito per verificare se un oggetto è una funzione se non si conteggia alcuna istanza di classe richiamabile come funzione, ma solo funzioni definite incorporate o con lambda , def o parziale .

E penso che questo avvolga tutto. Buona giornata!


1

In Python3 ho pensato a type (f) == type (lambda x:x)chi produce Truese fè una funzione e Falsese non lo è. Ma penso di preferire isinstance (f, types.FunctionType), che sembra meno ad hoc. Volevo farlo type (f) is function, ma non funziona.


0

Dopo le risposte precedenti, mi è venuto in mente questo:

from pprint import pprint

def print_callables_of(obj):
    li = []
    for name in dir(obj):
        attr = getattr(obj, name)
        if hasattr(attr, '__call__'):
            li.append(name)
    pprint(li)

0

Puoi provare questo:

if obj.__class__.__name__ in ['function', 'builtin_function_or_method']:
    print('probably a function')

o anche qualcosa di più bizzarro:

if "function" in lower(obj.__class__.__name__):
    print('probably a function')

-1

Se il codice continua per eseguire la chiamata se il valore è richiamabile, basta eseguire la chiamata e intercettare TypeError.

def myfunc(x):
  try:
    x()
  except TypeError:
    raise Exception("Not callable")

4
Questo è pericoloso; non hai idea di quali effetti collaterali xabbia.
cwallenpoole,

-2

Quello che segue è un "modo repr" per verificarlo. Funziona anche con lambda.

def a():pass
type(a) #<class 'function'>
str(type(a))=="<class 'function'>" #True

b = lambda x:x*2
str(type(b))=="<class 'function'>" #True

-3

Questo funziona per me:

str(type(a))=="<class 'function'>"

1
E cosa ci dice se il risultato è una stringa vuota? Per una funzione, ottengo "<type 'function'>", per un numero intero, ottengo "<type 'int'>", quindi non vedo come funziona per te: /
pawamoy

Ora funziona solo per Python 3 :) Inoltre, a seconda dell'intento originale della domanda, sarebbe incompleto: l' openintegrato dovrebbe essere considerato una funzione? str(type(open))<class 'builtin_function_or_method'>in Python 3.
pawamoy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.