Comment convertir une chaîne en une fonction en python?
Par exemple, si j'ai une fonction appelée ajouter comme
def add(x,y):
return x+y
Et je veux la possibilité de convertir une chaîne ou une entrée pour diriger vers cette fonction comme
w=raw_input('Please input the function you want to use')
Ou
w='add'
Est-il un moyen d'utiliser w pour désigner la fonction ajouter?
8 réponses
Puisque vous prenez une entrée utilisateur, le moyen le plus sûr est de définir exactement ce qui est une entrée valide:
dispatcher={'add':add}
w='add'
try:
function=dispatcher[w]
except KeyError:
raise ValueError('invalid input')
Si vous souhaitez évaluer les cordes, comme 'add(3,4)'
, vous pouvez utiliser sûr eval:
eval('add(3,4)',{'__builtins__':None},dispatcher)
eval
en général pourrait être dangereux lorsqu'il est appliqué à une entrée d'utilisateur. ce qui précède est plus sûr puisque __builtins__
est désactivé et locals
est limité à dispatcher
. Quelqu'un de plus intelligent que moi pourrait encore causer des problèmes, mais je ne pouvais pas vous dire comment faire il.
AVERTISSEMENT: Meme eval(..., {'__builtins__':None}, dispatcher)
est dangereux pour être appliqué à une entrée d'utilisateur. Un utilisateur malveillant peut exécuter des fonctions arbitraires sur votre machine s'il a la possibilité d'avoir sa chaîne évaluée par eval
.
Un moyen sûr est de mapper des noms aux fonctions. C'est plus sûr que d'utiliser 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.'
La solution D'Unutbu est ce que j'utiliserais normalement, mais par souci d'exhaustivité:
Si vous spécifiez le nom exact de la fonction, vous pouvez utiliser eval
, bien qu'il soit fortement déconseillé car les gens peuvent faire des choses malveillantes:
eval("add")(x,y)
La fonction intégrée eval
faire ce que vous souhaitez. Tous les Avertissements habituels concernant l'exécution de code arbitraire fourni par l'utilisateur s'appliquent.
S'il y a un nombre fini de fonctions prédéfinies, vous devriez éviter eval
et utiliser une table de recherche à la place (c'est-à-dire Dict
). Ne faites jamais confiance à vos utilisateurs.
Si vous implémentez une application de type shell dans laquelle l'utilisateur entre une commande (telle que add) et les réponses de l'application (renvoie la somme), vous pouvez utiliser le module cmd
, qui gère toutes les interactions de commande et la répartition pour vous. Voici un exemple:
#!/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')
Voici un exemple de session en cours d'exécution:
$ python cmd_tryout.py
tapez aide pour une liste de commandes valides
(Cmd) aide à ajouter
ajouter-ajoute deux numéros l'impression de la somme
(Cmd) ajouter 5 3
8
(Cmd) quitter
À l'invite (Cmd), vous pouvez émettre la help
commande que vous pouvez obtenir gratuitement. Les autres commandes sont add
et quit
, qui correspondent à la do_add()
et do_quit()
fonctions.
Notez que la commande help affiche la docstring de votre fonction. Le docstring est une chaîne qui suit immédiatement la déclaration de la fonction (Voir do_add()
par exemple).
Le module cmd
ne fait aucun argument spliting, l'analyse, donc vous devez le faire vous-même. La fonction do_add()
l'illustre.
Cet exemple de programme devrait être suffisant pour vous aider à démarrer. Pour plus d'informations, consultez la page d'aide cmd. Il est trivia pour personnaliser l'invite et d'autres aspects de votre programme.
J'ai eu beaucoup de situations où j'ai eu besoin de comparer une chaîne à un int et vice versa dans un modèle Django.
J'ai créé un filtre qui m'a permis de passer le nom de la fonction et d'utiliser eval () le convertir.
Exemple:
Modèle:
{% ifequal string int|convert:'str' %} do something {% endifequal %}
Filtre de modèle (où j'utilise une chaîne pour appeler le nom de la fonction):
@register.filter
def convert(value, funcname):
try:
converted = eval(funcname)(value)
return converted
except:
return value
Il suffit D'utiliser la référence de la fonction:
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')
Simple et sécurisé.
[ je suis arrivé ici via une question en double. Ma première pensée était d'utiliser argparse
et {[2] } et je ne l'ai pas vu ici, donc je l'ajoute comme une autre option.]
Vous pouvez utiliser argparse
pour configurer un registre de fonctions / commandes et analyser en toute sécurité leurs arguments. Cela fournira également un certain niveau de convivialité, par exemple en vous permettant de savoir quand vous avez entré une commande qui n'existe pas.
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()