2010-03-17 25 views
6

Poiché le funzioni sono valori in Python, come faccio a determinare se la variabile è una funzione?Come determinare se la variabile è una funzione in Python?

Ad esempio:

boda = len # boda is the length function now 
if ?is_var_function(boda)?: 
    print "Boda is a function!" 
else: 
    print "Boda is not a function!" 

Qui ipotetico ?is_var_function(x)? dovrebbe restituirla vero se x è una funzione callable, e falso se non lo è.

+0

Vuoi che ritorni vero anche per le classi, dal momento che sono richiamabili? – Javier

+4

La soluzione migliore è smettere di volerlo fare. –

+1

Cosa ti impedisce di leggere il codice? –

risposta

11

Il built-in callable indicato in altre risposte non risponde alla domanda come posta, poiché restituisce anche True, oltre alle funzioni, per metodi, classi, istanze di classi che definiscono un metodo __call__. Se il titolo e il testo della tua domanda sono sbagliati, e non ti importa se qualcosa è in realtà una funzione, ma solo se è , allora usa quel builtin. Ma la migliore risposta alla tua domanda è: importare il metodo inspect della libreria standard di Python e usare inspect.isfunction. (Ci sono altri modi di astrazione più bassa, ma è sempre una buona idea usare la funzionalità del modulo inspect per l'introspezione quando è lì, in preferenza agli approcci di livello inferiore: inspect aiuta a mantenere il codice conciso, chiaro, robusto e futuro -prova).

+1

Un'altra risposta errata accettata su SO. Dovrei iniziare una lista. Questo fallisce per le funzioni e i metodi di classe, come ho accennato in un paio di altre risposte. Dovresti anche controllare inspect.isbuiltin() e inspect.ismethod(), e non c'è nulla di "a prova di futuro" per avere tanti casi speciali. –

+0

E perché non digitare (a) == types.functionType? – AsTeR

7

C'è una funzione callable in python.

if callable(boda): 
+0

Una funzione/metodo è ogni oggetto che implementa un metodo '__call__'. callable() è un buon modo per verificare l'esistenza di un tale metodo di chiamata. – tux21b

+0

Ma anche callable restituirà true per una classe, non è vero? Non è chiaro se anche l'OP lo volesse. – Javier

+1

Sospetto che l'OP non conosca la differenza, e in realtà vuole qualcosa che si possa chiamare. È probabile che se non sai come controllare se qualcosa è una funzione in Python, in realtà non vuoi farlo. –

4

Usa callable(boda) per determinare se boda è callable o meno.

Callable significa che si tratta di una funzione, metodo o anche una classe. Ma dal momento che vuoi distinguere solo tra variabili e funzioni, dovrebbe funzionare bene.

Il tuo codice sarebbe quindi simile:

boda = len # boda is the length function now 
if callable(boda): 
    print "Boda is a function!" 
else: 
    print "Boda is not a function!" 
2
>>> import types 
>>> def f(): pass 
... 
>>> x = 0 
>>> type(f) == types.FunctionType 
True 
>>> type(x) == types.FunctionType 
False 

Questo controllerà se si tratta di una funzione. callable() controllerà se è richiamabile (vale a dire, ha un metodo __call__), quindi restituirà true su una classe, nonché su una funzione o un metodo.

+0

"isinstance" è generalmente preferito per typechecking. 'is' è generalmente preferito su' == 'per il controllo dei singleton.Richiedere una funzione e non qualcos'altro che agisce esattamente come una funzione è una cattiva politica. –

+1

'type (sys.exit) == types.FunctionType' e' type ((1.0) .hex) == types.FunctionType' sono entrambi falsi. (Ancora non riesce con isinstance, non so perché BuiltinFunctionType e MethodType non sono sottoclassi di FunctionType.) –

11

È possibile utilizzare inspect.isfunction(object). Vedi: docs.python.org

Detto questo, dovresti evitare di utilizzare questa tecnica nel tuo codice giornaliero. A volte è effettivamente necessario utilizzare la riflessione - ad esempio, un framework MVC potrebbe dover caricare una classe e ispezionare i suoi membri. Ma di solito dovresti restituire/passare/gestire gli oggetti che hanno la stessa "interfaccia". Ad esempio, non restituire un oggetto che potrebbe essere un numero intero o una funzione - restituire sempre lo stesso "tipo" di oggetto in modo che il codice possa essere coerente.

+0

@Justin Ethier - sembra che qualcuno abbia downvotato ogni risposta. – kgrad

+1

Fornisce consigli su come fare qualcosa che di solito è cattivo senza contesto su come costruire un codice Python buono, robusto e idiomatico. –

+3

Capita anche di rispondere alla domanda, che è lo scopo di questo sito. – harto

0

E che cosa deve restituire per un property, a cui si accede come un attributo valore ma in realtà richiama una funzione? La tua domanda apparentemente semplice in realtà apre un intero barattolo di worm in Python. Il che significa che cose come callable e isfunction sono utili per la tua educazione e introspezione, ma probabilmente non sono cose su cui vuoi fare affidamento quando ti interfaccia con un altro codice.

Tangenzialmente: vedere la presentazione Turtles All The Way Down per ulteriori informazioni su come Python viene messo insieme.

+1

Una proprietà è uno strano esempio. Le proprietà non agiscono in modo molto simile alle funzioni e, più precisamente, in una situazione normale non si accede all'oggetto proprietà reale, si accede all'oggetto che ha ottenuto per te. –

1

La filosofia di come utilizzare diversi oggetti in un programma Python si chiama digitazione anatra -se sembra un'anatra, ciarlatana come anatra, e cammina come un'anatra, è un'anatra. Gli oggetti non sono raggruppati in base al loro tipo ma a ciò che sono in grado di fare, e questo si estende anche alle funzioni. Quando scrivi un programma Python, dovresti sempre sapere cosa possono fare tutti gli oggetti e usarli senza controllo.

Ad esempio, ho potuto definire una funzione

def add_three(a, b c): 
    return a + b + c 

e significare per essere utilizzato con tre galleggianti. Ma non controllando questo, ho una funzione molto più utile: posso usarla con ints, con decimal.Decimals, o con fractions.Fractions, per esempio.

Lo stesso vale per avere una funzione. Se so di avere una funzione e voglio chiamarla, dovrei semplicemente chiamarla. Forse quello che ho è una funzione e forse ho un altro callable (come un metodo associato o un'istanza di una classe arbitraria che definisce __call__) che potrebbe essere altrettanto buono. Non controllando nulla, faccio in modo che il mio codice sia in grado di gestire una vasta gamma di circostanze che non avrei nemmeno potuto pensare in anticipo.

Nel caso delle callebles, posso determinare in modo affidabile se ne possiedo una o meno, ma per la semplicità del mio codice, non dovrei volerlo. Se qualcuno passa in qualcosa che non è chiamabile, riceverai un errore quando lo chiami comunque. Se sto scrivendo un codice che accetta un parametro che può essere un callable o meno e faccio cose diverse a seconda di esso, sembra che dovrei migliorare la mia API definendo due funzioni per fare queste due cose diverse.

Se si dispone di un modo per gestire il caso in cui il chiamante ha inoltrato qualcosa che non è simile alla funzione (e questo non era solo il risultato di un'API folle), la soluzione giusta sarebbe prendere il TypeError che viene generato quando si tenta di chiamare qualcosa che non può essere chiamato. In generale, è meglio provare a fare qualcosa e recuperare se fallisce piuttosto che controllare in anticipo. (Ricorda il cliché, "È più facile chiedere perdono che il permesso.") Controllare in anticipo può portare a problemi imprevisti basati su sottili errori di logica e può portare a condizioni di gara.

Perché pensi di aver bisogno di tipografare?

Problemi correlati