una - funciones string python
¿Cómo convertir una cadena a una función en python? (8)
He tenido muchas situaciones en las que he necesitado comparar una cadena con un int y viceversa dentro de una plantilla de Django.
Creé un filtro que me permitió pasar el nombre de la función y al usar eval () convertirlo.
Ejemplo:
Modelo:
{% ifequal string int|convert:''str'' %} do something {% endifequal %}
Filtro de plantilla (donde uso una cadena para llamar al nombre de la función):
@register.filter
def convert(value, funcname):
try:
converted = eval(funcname)(value)
return converted
except:
return value
Por ejemplo, si tengo una función llamada agregar como
def add(x,y):
return x+y
y quiero la capacidad de convertir una cadena o una entrada para dirigir a esa función como
w=raw_input(''Please input the function you want to use'')
o
w=''add''
¿Hay alguna forma de usar w para referirse a la función agregar?
La solución de unutbu es la que usaría normalmente, pero para completar:
Si está especificando el nombre exacto de la función, puede usar eval
, aunque está muy desaconsejado porque la gente puede hacer cosas maliciosas:
eval("add")(x,y)
Si está implementando una aplicación tipo shell donde el usuario ingresa algún comando (como agregar ), y las respuestas de la aplicación (devuelva la suma), puede usar el módulo cmd
, que maneja todas las interacciones y el envío del comando por usted. Aquí hay un ejemplo:
#!/usr/bin/env python
import cmd
import shlex
import sys
class MyCmd(cmd.Cmd):
def do_add(self, arguments):
''''''add - Adds two numbers the print the sum''''''
x, y = shlex.split(arguments)
x, y = int(x), int(y)
print x + y
def do_quit(self, s):
''''''quit - quit the program''''''
sys.exit(0)
if __name__ == ''__main__'':
cmd = MyCmd()
cmd.cmdloop(''type help for a list of valid commands'')
Aquí hay una sesión de muestra de ejecución:
$ python cmd_tryout.py
escriba ayuda para una lista de comandos válidos
(Cmd) ayuda agregar
sumar - Agrega dos números al imprimir la suma
(Cmd) agregar 5 3
8
(Cmd) quit
Cuando se le solicite (Cmd) , puede emitir el comando de help
que obtiene de forma gratuita. Otros comandos son add
y quit
que corresponden a las do_add()
y do_quit()
.
Tenga en cuenta que el comando de ayuda muestra la cadena de documentos para su función. La cadena de documentación es una cadena que sigue inmediatamente a la función de do_add()
vea do_add()
por ejemplo).
El módulo cmd
no hace ningún argumento de división, análisis, por lo que debe hacerlo usted mismo. La función do_add()
ilustra esto.
Este programa de ejemplo debería ser suficiente para que comiences. Para más información, consulte la página de ayuda de cmd . Es trivial personalizar el mensaje y otros aspectos de su programa.
Solo usa la referencia de la función:
import argparse
import shlex
def hello(name):
print(''hello,'', name)
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
hello_parser = subparsers.add_parser(''hello'')
hello_parser.add_argument(''name'')
hello_parser.set_defaults(func=hello)
print(''Enter q to quit'')
while True:
command = input(''command> '')
command = command.strip()
if not command:
continue
if command.lower() == ''q'':
break
words = shlex.split(command)
try:
args = parser.parse_args(words)
except SystemExit:
# argparse will sys.exit() on -h and errors; prevent that
continue
func_args = {name: value for name, value in vars(args).items()}
del func_args[''func'']
args.func(**func_args)
if __name__ == ''__main__'':
try:
main()
except KeyboardInterrupt:
print()
Sencillo y seguro.
Una forma segura es asignar desde nombres a funciones. Es más seguro que usar eval
.
function_mappings = {
''add'': add,
}
def select_function():
while True:
try:
return function_mappings[raw_input(''Please input the function you want to use'')]
except KeyError:
print ''Invalid function, try again.''
Ya que está tomando la entrada del usuario, la forma más segura es definir exactamente cuál es la entrada válida:
dispatcher={''add'':add}
w=''add''
try:
function=dispatcher[w]
except KeyError:
raise ValueError(''invalid input'')
Si desea evaluar cadenas como ''add(3,4)''
, podría usar la evaluación segura :
eval(''add(3,4)'',{''__builtins__'':None},dispatcher)
eval
en general podría ser peligrosa cuando se aplica a la entrada del usuario. Lo anterior es más seguro ya que __builtins__
está deshabilitado y los locals
están restringidos al dispatcher
.Alguien más listo que yo podría causar problemas, pero no podría decirte cómo hacerlo.
ADVERTENCIA: Incluso eval(..., {''__builtins__'':None}, dispatcher)
no es seguro para aplicar a la entrada del usuario. Un usuario malintencionado podría ejecutar funciones arbitrarias en su máquina si se le da la oportunidad de que su cadena sea evaluada por eval
.
[Llegué aquí a través de una pregunta duplicada. Mi primer pensamiento fue usar argparse
y shlex
y no lo vi aquí, así que lo estoy agregando como otra opción.]
Podría usar argparse
para configurar un registro de funciones / comandos y analizar de forma segura sus argumentos. Esto también proporcionará cierto nivel de facilidad de uso para, por ejemplo, avisarle cuando haya ingresado un comando que no existe.
def pwr(x, y):
return x ** y
def add(x, y):
return x + y
dispatcher = { ''pwr'' : pwr, ''add'' : add}
def call_func(x, y, func):
try:
return dispatcher[func](x, y)
except:
return "Invalid function"
call_func(2, 3, ''add'')
La función incorporada eval
hará lo que quieras. Se aplican todas las advertencias habituales sobre la ejecución de código arbitrario proporcionado por el usuario.
Si hay un número finito de funciones predefinidas, debe evitar eval
y usar una tabla de búsqueda (es decir, Dict
). Nunca confíes en tus usuarios.