2010-02-04 11 views
10

Questo è per l'uso in un'API JSON. Io non voglio avere:Python: come si chiama un metodo quando si ha solo il nome stringa del metodo?

if method_str == 'method_1': 
    method_1() 

if method_str == 'method_2': 
    method_2() 

Per ovvie ragioni questo non è ottimale. Come potrei usare le stringhe della mappa su metodi come questo in un modo riusabile (notare anche che ho bisogno di passare argomenti alle funzioni chiamate).

Ecco un esempio:

INCOMING JSON:

{ 
    'method': 'say_something', 
    'args': [ 
     135487, 
     'a_465cc1' 
    ] 
    'kwargs': { 
     'message': 'Hello World', 
     'volume': 'Loud' 
    } 
} 

# JSON would be turned into Python with Python's built in json module. 

chiamata risultante:

# Either this 
say_something(135487, 'a_465cc1', message='Hello World', volume='Loud') 

# Or this (this is more preferable of course) 
say_something(*args, **kwargs) 
+0

dupe molte volte su – SilentGhost

+0

dupe: http://stackoverflow.com/questions/680941/python-dynamic-function-names – SilentGhost

+0

Se non è per l'utilizzo in un'API, rispetto al perché menziona JSON in entrata e con il metodo nome specificato nell'oggetto JSON? Pensi che sia così che posso costruire una stringa JSON nel mio codice Python e poi passarla per chiamare i metodi? – orokusaki

risposta

23

Per i metodi delle istanze, utilizzare getattr

>>> class MyClass(object): 
... def sayhello(self): 
... print "Hello World!" 
... 
>>> m=MyClass() 
>>> getattr(m,"sayhello")() 
Hello World! 
>>> 

Per le funzioni si può guardare nel dict globale

>>> def sayhello(): 
... print "Hello World!" 
... 
>>> globals().get("sayhello")() 
Hello World! 

In questo caso, dal momento che ci non è una funzione chiamata prove_riemann_hypothesis la funzione predefinita (sayhello) viene utilizzato

>>> globals().get("prove_riemann_hypothesis", sayhello)() 
Hello World! 

Il problema con questo approccio è che si condivide lo spazio dei nomi con qualsiasi altra cosa è in là. Si potrebbe desiderare di proteggere contro i metodi di chiamata JSON che non è previsto per. Un buon modo per fare questo è decorare le tue funzioni in questo modo

>>> json_functions={} 
>>> def make_available_to_json(f): 
... json_functions[f.__name__]=f 
... return f 
... 
>>> @make_available_to_json 
... def sayhello(): 
... print "Hello World!" 
... 
>>> json_functions.get("sayhello")() 
Hello World! 
>>> json_functions["sayhello"]() 
Hello World! 
>>> json_functions.get("prove_riemann_hypothesis", sayhello)() 
Hello World! 
+0

La tua soluzione finale sembra chiamare magicamente la funzione. Non dovrebbe essere 'json_functions.get (" sayhello ")()' o meglio 'json_functions.ottenere [ "SayHello"]() '? È da una sessione di interprete vero? –

+0

@Mike, alcuni di questi sono :) –

+0

@gnibbler, perché preferisco ancora il metodo 'get' a' [] '? Quest'ultima è la sintassi naturale e, se "" sayhello "" non è valida, genera un'eccezione più significativa. –

1

assumendo le funzioni sono tutte variabili globali (sono, a meno che sono definite all'interno di un'altra funzioni), è possibile accedervi con la funzione globals(). globals() restituisce un dizionario di tutte le variabili globali, incluse le funzioni.

Ad esempio:

$ python 
Python 2.6.2 (r262:71600, Apr 16 2009, 09:17:39) 
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> def some_function(): 
...  print "Hello World!" 
... 
>>> globals() 
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'some_function': <function some_function at 0x6326b0>, '__package__': None} 
>>> globals()['some_function']() 
Hello World! 
+2

Per l'esempio dato, questo potrebbe essere davvero insicuro - non vi è alcuna garanzia che INCOMING_JSON provenga da una fonte amichevole. Includere una whitelist di funzioni o utilizzare la soluzione di Mike. – spookylukey

6

Utilizzare getattr. Per esempio:

class Test(object): 
    def say_hello(self): 
     print 'Hell no, world!!111' 
    def test(self): 
     getattr(self, 'say_hello')() 
+0

e il metodo '{'': '__init __', ...' –

6

Il modo pulito e sicuro per farlo è di fare una mappatura nomi dict alle funzioni. Se questi sono in realtà metodi, il modo migliore è ancora di fare un tale dict, anche se getattr è anche disponibile. L'utilizzo di globals o eval non è sicuro e sporco.

Problemi correlati