Comment exécuter une chaîne contenant du code Python en Python?
Comment exécuter une chaîne contenant du code Python en Python?
Réponses:
Pour les instructions, utilisez exec(string)
(Python 2/3) ou exec string
(Python 2):
>>> mycode = 'print "hello world"'
>>> exec(mycode)
Hello world
Lorsque vous avez besoin de la valeur d'une expression, utilisez eval(string)
:
>>> x = eval("2+2")
>>> x
4
Cependant, la première étape devrait être de vous demander si vous en avez vraiment besoin. L'exécution du code devrait généralement être la position de dernier recours: elle est lente, laide et dangereuse si elle peut contenir du code saisi par l'utilisateur. Vous devriez toujours regarder d'abord les alternatives, telles que les fonctions d'ordre supérieur, pour voir si celles-ci peuvent mieux répondre à vos besoins.
if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42
etc, dans lequel il peut ensuite écrire exec ("x.%s = 42" % s)
. Pour ce cas courant (où vous avez seulement besoin d'accéder à l'attribut d'un objet qui est stocké dans une chaîne), il existe une fonction beaucoup plus rapide, plus propre et plus sûre getattr
: il suffit d'écrire getattr(x, s) = 42
pour signifier la même chose.
setattr(x, s, 42)
? J'ai essayé getattr(x, 2) = 42
et cela a échoué aveccan't assign to function call: <string>, line 1
setattr(x, s, 42)
c'est la bonne syntaxe. Surpris, il a fallu si longtemps pour que cette erreur soit détectée. Quoi qu'il en soit, le fait est que getattr
et setattr
sont une alternative au exec
moment où tout ce que vous voulez est d'obtenir un membre arbitraire, recherché par chaîne.
Dans l'exemple, une chaîne est exécutée en tant que code à l'aide de la fonction exec.
import sys
import StringIO
# create file-like string to capture output
codeOut = StringIO.StringIO()
codeErr = StringIO.StringIO()
code = """
def f(x):
x = x + 1
return x
print 'This is my output.'
"""
# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr
exec code
# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
print f(4)
s = codeErr.getvalue()
print "error:\n%s\n" % s
s = codeOut.getvalue()
print "output:\n%s" % s
codeOut.close()
codeErr.close()
exec
du tout (sauf si vous savez que la chaîne de code provient d'une source fiable).
eval
et exec
sont la bonne solution, et ils peuvent être utilisés de manière plus sûre .
Comme expliqué dans le manuel de référence de Python et clairement expliqué dans ce tutoriel, les fonctions eval
et exec
prennent deux paramètres supplémentaires qui permettent à un utilisateur de spécifier les fonctions et variables globales et locales disponibles.
Par exemple:
public_variable = 10
private_variable = 2
def public_function():
return "public information"
def private_function():
return "super sensitive information"
# make a list of safe functions
safe_list = ['public_variable', 'public_function']
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
# add any needed builtins back in
safe_dict['len'] = len
>>> eval("public_variable+2", {"__builtins__" : None }, safe_dict)
12
>>> eval("private_variable+2", {"__builtins__" : None }, safe_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'private_variable' is not defined
>>> exec("print \"'%s' has %i characters\" % (public_function(), len(public_function()))", {"__builtins__" : None}, safe_dict)
'public information' has 18 characters
>>> exec("print \"'%s' has %i characters\" % (private_function(), len(private_function()))", {"__builtins__" : None}, safe_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'private_function' is not defined
En substance, vous définissez l'espace de noms dans lequel le code sera exécuté.
eval
ou exec
sont destinés à être utilisés comme exec(input("Type what you want"))
? Il existe de nombreux cas où un programme peut écrire une procédure ou une fonction à la suite d'un calcul; les fonctions résultantes seront aussi sûres et aussi rapides (une fois évaluées) que toute autre partie d'un bon programme bien écrit. Un programme dangereux contenant exec
n'est pas plus dangereux qu'un programme dangereux faisant lui-même les dégâts car exec
il ne donne aucun nouveau privilège au programme.
exec
eteval
exec
eteval
en Python est très mal vu.De la réponse du haut (accent sur le mien):
Pour les instructions, utilisez
exec
.Lorsque vous avez besoin de la valeur d'une expression, utilisez
eval
.Cependant, la première étape devrait être de vous demander si vous en avez vraiment besoin. L'exécution du code devrait généralement être la position de dernier recours : elle est lente, laide et dangereuse si elle peut contenir du code saisi par l'utilisateur. Vous devriez toujours regarder d' abord les alternatives, telles que les fonctions d'ordre supérieur , pour voir si celles-ci peuvent mieux répondre à vos besoins.
Des alternatives à exec / eval?
définir et obtenir des valeurs de variables avec les noms dans les chaînes
[tandis que
eval
] fonctionnerait, il n'est généralement pas conseillé d'utiliser des noms de variables ayant une signification pour le programme lui-même.Au lieu de cela, mieux vaut utiliser un dict.
De http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (accent sur le mien)
Python n'est pas PHP
N'essayez pas de contourner les idiomes Python car un autre langage le fait différemment. Les espaces de noms sont en Python pour une raison et juste parce qu'il vous donne l'outil,
exec
cela ne signifie pas que vous devez utiliser cet outil.
Sur http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (c'est moi qui souligne)
Donc eval n'est pas sûr, même si vous supprimez tous les globaux et les builtins!
Le problème avec toutes ces tentatives pour protéger eval () est qu'il s'agit de listes noires . Ils suppriment explicitement les choses qui pourraient être dangereuses. C'est une bataille perdue car s'il n'y a qu'un seul élément à gauche de la liste, vous pouvez attaquer le système .
Alors, eval peut-il être sécurisé? Dur à dire. À ce stade, ma meilleure supposition est que vous ne pouvez pas faire de mal si vous ne pouvez pas utiliser de soulignements doubles, alors peut-être que si vous excluez une chaîne avec des soulignements doubles, vous êtes en sécurité. Peut être...
De http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (c'est moi qui souligne):
Premièrement,
exec
il est plus difficile pour les êtres humains de lire votre code . Afin de comprendre ce qui se passe, je n'ai pas seulement à lire votre code, je dois lire votre code, comprendre quelle chaîne il va générer, puis lire ce code virtuel. Donc, si vous travaillez en équipe, que vous publiez un logiciel open source ou que vous demandez de l'aide quelque part comme StackOverflow, il est plus difficile pour les autres de vous aider. Et s'il y a une chance que vous déboguiez ou développiez ce code dans 6 mois, vous vous compliquez la tâche directement.
cfg.yaml
):, reldir : ../my/dir/
et reldir = cfg[reldir]
. Cependant, comme ce code python doit fonctionner à la fois sur Windows et Linux, j'en ai besoin pour m'adapter aux différents diviseurs de chemin des systèmes d'exploitation; soit \\
ou /
. J'utilise donc reldir : os.path.join('..','my','dir')
dans le fichier de configuration. Mais cela ne fait reldir
qu'être cette chaîne littérale, non évaluée, donc je ne peux pas ouvrir un fichier dans reldir
. Avez-vous une suggestion?
Vous effectuez l'exécution de code à l'aide de exec, comme avec la session IDLE suivante:
>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']
4
Comme les autres l'ont mentionné, c'est "exec" ..
mais, si votre code contient des variables, vous pouvez utiliser "global" pour y accéder, également pour empêcher le compilateur de générer l'erreur suivante:
NameError: le nom 'p_variable' n'est pas défini
exec('p_variable = [1,2,3,4]')
global p_variable
print(p_variable)
Il convient de mentionner que ce exec
frère existe aussi bien appeléexecfile
si vous voulez appeler un fichier python. C'est parfois bon si vous travaillez dans un package tiers qui contient de terribles IDE et que vous souhaitez coder en dehors de leur package.
Exemple:
execfile('/path/to/source.py)'
ou:
exec(open("/path/to/source.py").read())
J'ai essayé pas mal de choses, mais la seule chose qui fonctionnait était la suivante:
temp_dict = {}
exec("temp_dict['val'] = 10")
print(temp_dict['val'])
production:
10
Ok. Je sais que ce n'est pas exactement une réponse, mais peut-être une note pour les gens qui regardent ça comme moi. Je voulais exécuter du code spécifique pour différents utilisateurs / clients, mais je voulais également éviter l'exec / eval. J'ai d'abord cherché à stocker le code dans une base de données pour chaque utilisateur et à faire ce qui précède.
J'ai fini par créer les fichiers sur le système de fichiers dans un dossier 'customer_filters' et en utilisant le module 'imp', si aucun filtre ne s'appliquait pour ce client, il a simplement continué
import imp
def get_customer_module(customerName='default', name='filter'):
lm = None
try:
module_name = customerName+"_"+name;
m = imp.find_module(module_name, ['customer_filters'])
lm = imp.load_module(module_name, m[0], m[1], m[2])
except:
''
#ignore, if no module is found,
return lm
m = get_customer_module(customerName, "filter")
if m is not None:
m.apply_address_filter(myobj)
donc customerName = "jj" exécuterait apply_address_filter à partir du fichier customer_filters \ jj_filter.py