2010-02-04 12 views
10

Esto es para usar en una API JSON. no quiere tener:Python: ¿Cómo llamas a un método cuando solo tienes el nombre de la cadena del método?

if method_str == 'method_1': 
    method_1() 

if method_str == 'method_2': 
    method_2() 

Por razones obvias, esto no es óptima. ¿Cómo usaría cadenas de mapa para métodos como este de forma reutilizable (también tenga en cuenta que necesito pasar argumentos a las funciones llamadas).

Aquí se muestra un ejemplo:

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

llamada resultante:

# 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 muchas veces más – SilentGhost

+0

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

+0

Si no es para usar en una API, entonces ¿por qué menciona el JSON entrante y el método? nombre especificado en el objeto JSON? ¿Crees que es así que puedo construir una cadena JSON en mi código Python y luego pasarlo a los métodos de llamada? – orokusaki

Respuesta

23

Para los métodos de los casos, utilizar getattr

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

Para las funciones que usted puede buscar en el dict mundial

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

En este caso, ya que hay no hay función llamada prove_riemann_hypothesis la función predeterminada (sayhello) se utiliza

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

El problema con este enfoque es que está compartiendo el espacio de nombres con cualquier otra cosa que está ahí. Es posible que desee proteger contra los métodos de llamada json no se supone que. Una buena forma de hacerlo es decorar sus funciones de esta manera

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

Su solución final parece llamar mágicamente a la función. ¿No debería ser 'json_functions.get (" sayhello ")()' o mejor 'json_functions.obtener ["sayhello"]() '? ¿Es eso de una sesión de intérprete real? –

+0

@Mike, parte de ella es :) –

+0

@gnibbler, ¿por qué todavía prefieren el método 'get' a' [] '? Esta última es la sintaxis natural y, si '" sayhello "' no es válida, arroja una excepción más significativa. –

1

Suponiendo que las funciones son todas las variables globales (que son, a menos que se definen dentro de otro funciones), se puede acceder con la función globals(). globals() devuelve un diccionario de todas las variables globales, incluidas las funciones.

Por ejemplo:

$ 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

Para el ejemplo dado, esto podría ser realmente inseguro; no hay garantía de que INCOMING_JSON sea de una fuente amigable. Incorpore una lista blanca de funciones o use la solución de Mike. – spookylukey

6

Usar getattr. Por ejemplo:

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

¿qué pasa con '{'method': '__init __', ...' –

6

La forma limpia, segura de hacer esto es hacer un mapeo de nombres a las funciones dict. Si estos son en realidad métodos, la mejor manera es hacer tal dict, aunque getattr también está disponible. El uso de globals o eval es inseguro y sucio.

Cuestiones relacionadas