Comment exécuter une chaîne contenant du code Python en Python?
Dans l'exemple, une chaîne est exécutée sous forme de 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()
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 doit généralement être la position de dernier recours: c'est lent, moche et dangereux s'il peut contenir un code saisi par l'utilisateur. Vous devez toujours commencer par rechercher des alternatives, telles que les fonctions d'ordre supérieur, pour voir si elles peuvent mieux répondre à vos besoins.
Rappelez-vous que depuis la version 3 exec
est une fonction!
utilisez toujours exec(mystring)
au lieu de exec mystring
.
eval
et exec
sont la solution correcte et peuvent être utilisés de manière plus sûre.
Comme indiqué dans Le manuel de référence de Python et expliqué clairement dans this tutorial, les fonctions eval
et exec
prennent deux paramètres supplémentaires qui permettent à l'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()
est juste pour les expressions, alors que eval('x+1')
fonctionne, eval('x=1')
ne fonctionnera pas par exemple. Dans ce cas, il vaut mieux utiliser exec
, ou même mieux: essayez de trouver une meilleure solution :)
Vous exécutez le code en utilisant exec, comme avec la session IDLE suivante:
>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']
4
exec
et eval
exec
et eval
en Python est très mal vu.De la réponse du haut (souligné par moi):
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 doit généralement être la position de dernier recours: c'est lent, moche et dangereux s'il peut contenir un code saisi par l'utilisateur. Vous devez toujours commencer par examiner les options , telles que les fonctions d'ordre supérieur, pour voir si elles peuvent mieux répondre à vos besoins.
définir et obtenir des valeurs de variables avec les noms dans des chaînes
[Alors que
eval
] fonctionnerait, il est généralement déconseillé d'utiliser des noms de variable ayant une signification pour le programme lui-même.Au lieu de cela, mieux utiliser un dict.
De http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (l'emphase mienne)
Python n'est pas PHP
N'essayez pas de contourner les idiomes Python, car une autre langue le fait différemment. Les espaces de noms sont en Python pour une raison et juste parce que cela vous donne l'outil
exec
cela ne signifie pas que vous devriez utiliser cet outil.
De 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 globals et les éléments intégrés!
Le problème avec toutes ces tentatives de protection de eval () est qu’elles sont des listes noires. Ils suppriment explicitement les choses qui pourraient être dangereuses. C'est une bataille perdue d'avance car s'il ne reste qu'un élément à gauche de la liste, vous pouvez attaquer le système.
Alors, peut-on sécuriser eval? Dur à dire. A ce stade, ma meilleure hypothèse est que vous ne pouvez pas faire de mal si vous ne pouvez utiliser aucun double trait de soulignement. Par conséquent, si vous excluez une chaîne comportant un double soulignement, 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
rend plus difficile la lecture de votre code par les êtres humains. Afin de comprendre ce qui se passe, je ne dois pas simplement lire votre code, je dois le lire, déterminer quelle chaîne il va générer, puis lire ce code virtuel. Ainsi, si vous travaillez en équipe, éditez des logiciels open source ou demandez de l'aide, par exemple StackOverflow, vous empêchez les autres de vous aider. Et s'il y a une chance que vous développiez ou développiez ce code dans 6 mois, vous le rendez plus difficile pour vous-même.
Départ eval :
x = 1
print eval('x+1')
->2
La solution la plus logique serait d'utiliser la fonction eval () . Une autre solution consiste à écrire cette chaîne dans un fichier python temporaire et à l'exécuter.
Utilisez eval .
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)
Ok .. Je sais que ce n’est pas vraiment une réponse, mais peut-être une note pour ceux qui le regardent comme moi. Je voulais exécuter du code spécifique pour différents utilisateurs/clients, mais je voulais aussi éviter le exec/eval. Au départ, je cherchais à 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 n'était appliqué à ce client, cela fonctionnait
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)
so customerName = "jj" exécuterait apply_address_filter à partir du fichier customer_filters\jj_filter.py