Pour être juste, contrairement à l'autre question, celle-ci n'est pas un doublon. Et d'autres ont posé des questions beaucoup plus fondamentales que cela.
DNS
8
La bonne réponse, bien sûr, est presque toujours «non!».
bobince
23
@S. Lott: Vous n'avez pas lu la FAQ récemment? "Il est également parfaitement bien de poser et de répondre à votre propre question de programmation, mais faites comme si vous étiez sur Jeopardy: formulez-le sous la forme d'une question". Ce n'est pas une mauvaise question. +1
Devin Jeanpierre
49
@ S.Lott: Non. Vous n'en avez pas besoin. Si la question n'est pas déjà sur le site, alors c'est un jeu équitable (selon la FAQ, comme déjà indiqué). Répondez à chaque question comme si le PO avait besoin d'aide. Peut-être pas, mais le prochain qui lira leur question le fera probablement. Juste mes 2 cents.
Bill the Lizard
1
À tous ceux qui vous disent de ne pas le faire: j'ai un cas où j'en ai absolument besoin. Il s'agit d'un traitement distribué.
>>> 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.
mais qu'en est-il de la portée du code exécuté par 'exec'? est-il imbriqué?
jondinham
21
Un cas courant où quelqu'un veut utiliser 'exec' est quelque chose comme if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42etc, 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) = 42pour signifier la même chose.
ShreevatsaR
5
Comment exec est-il plus lent que l'interpréteur python?
Cris Stringfellow
6
@ShreevatsaR ne voulez-vous pas dire setattr(x, s, 42)? J'ai essayé getattr(x, 2) = 42et cela a échoué aveccan't assign to function call: <string>, line 1
Tanner Semerad
6
@Tanner: Hmm. Oui, en effet, 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 getattret setattrsont une alternative au execmoment où tout ce que vous voulez est d'obtenir un membre arbitraire, recherché par chaîne.
ShreevatsaR
68
Dans l'exemple, une chaîne est exécutée en tant que code à l'aide de la fonction exec.
import sys
importStringIO# 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()
échanger stdout et stderr comme ça me rend très nerveux. il semble que cela puisse causer d'énormes problèmes de sécurité. y a-t-il un moyen de contourner cela?
Narcolapser
1
@Narcolapser, vous devriez être plus soucieux d'utiliser execdu tout (sauf si vous savez que la chaîne de code provient d'une source fiable).
bruno desthuilliers
27
evalet execsont 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 evalet execprennent 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 =2def 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'isnot 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'isnot defined
En substance, vous définissez l'espace de noms dans lequel le code sera exécuté.
Il n'est pas possible de rendre eval sûr: Eval est vraiment dangereux . Si vous prenez le code de moi et que vous l'évaluez, je peux créer un défaut de votre programme Python. Jeu terminé.
Ned Batchelder
3
@ v.oddou Je répondais à la déclaration d'alan, "eval et exec .. peuvent être utilisés de manière sûre." C'est faux. Si quelqu'un disait: «bash peut être utilisé de manière sûre», ce serait également faux. Bash est dangereux. C'est un danger nécessaire, mais dangereux néanmoins. Prétendre que l'eval peut être sécurisé est tout simplement faux.
Ned Batchelder
1
@NedBatchelder oui en effet. et le lien vers lequel vous pointez est un bon matériel. avec le pouvoir vient la responsabilité, il s'agit donc simplement d'être conscient du pouvoir potentiel de l'eval. et si nous décidons que puissance = danger.
v.oddou
3
@NedBatchelder De nombreux morceaux de code écrits en Python peuvent également être dangereux, mais pourquoi supposez-vous que evalou execsont 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 execn'est pas plus dangereux qu'un programme dangereux faisant lui-même les dégâts car execil ne donne aucun nouveau privilège au programme.
Thomas Baruchel
1
@ThomasBaruchel encore une fois, mon point est de contrer l'idée que eval ou exec peuvent être sécurisés. En particulier, cette réponse affirme que le contrôle des globaux et des locaux permettra de les utiliser en toute sécurité. C'est faux. Chaque fois que vous utilisez exec et eval, vous devez savoir précisément quel code est exécuté. Si vous ne le faites pas, alors vous êtes ouvert aux opérations dangereuses.
Ned Batchelder
21
N'oubliez pas que la version 3 execest une fonction!
utilisez donc toujours exec(mystring)au lieu de exec mystring.
eval()est juste pour les expressions, tandis que eval('x+1')fonctionne, eval('x=1')ne fonctionnera pas par exemple. Dans ce cas, il vaut mieux l'utiliser exec, ou encore mieux: essayez de trouver une meilleure solution :)
Utilisation de execeteval en Python est très mal vu.
Il existe de meilleures alternatives
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.
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.
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, execcela ne signifie pas que vous devez utiliser cet outil.
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...
Premièrement, execil 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.
"ma meilleure supposition est que vous ne pouvez pas faire de mal si vous ne pouvez pas utiliser de doubles soulignés" - Vous pouvez construire une chaîne contenant des doubles soulignés, puis appeler valider cette chaîne.
Stanley Bak
de bons conseils, à moins que vous n'écriviez un générateur de code, un gestionnaire de travaux ou similaire ... ce que la plupart des gens font probablement ici.
Erik Aronesty
Je dois importer un chemin relatif à partir d'un fichier de configuration ( 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 reldirqu'être cette chaîne littérale, non évaluée, donc je ne peux pas ouvrir un fichier dans reldir. Avez-vous une suggestion?
Marie. P.
9
Vous effectuez l'exécution de code à l'aide de exec, comme avec la session IDLE suivante:
Cela ne fonctionne pas en python normal. Du moins pas en python 3.
Thomas Ahle
6
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:
Il convient de mentionner que ce execfrè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.
La solution la plus logique serait d'utiliser la fonction intégrée eval () . Une autre solution consiste à écrire cette chaîne dans un fichier python temporaire et à l'exécuter.
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 =Nonetry:
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 isnotNone:
m.apply_address_filter(myobj)
donc customerName = "jj" exécuterait apply_address_filter à partir du fichier customer_filters \ jj_filter.py
Réponses:
Pour les instructions, utilisez
exec(string)
(Python 2/3) ouexec string
(Python 2):Lorsque vous avez besoin de la valeur d'une expression, utilisez
eval(string)
: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.
la source
if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42
etc, dans lequel il peut ensuite écrireexec ("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ûregetattr
: il suffit d'écriregetattr(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 quegetattr
etsetattr
sont une alternative auexec
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.
la source
exec
du tout (sauf si vous savez que la chaîne de code provient d'une source fiable).eval
etexec
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
etexec
prennent deux paramètres supplémentaires qui permettent à un utilisateur de spécifier les fonctions et variables globales et locales disponibles.Par exemple:
En substance, vous définissez l'espace de noms dans lequel le code sera exécuté.
la source
eval
ouexec
sont destinés à être utilisés commeexec(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 contenantexec
n'est pas plus dangereux qu'un programme dangereux faisant lui-même les dégâts carexec
il ne donne aucun nouveau privilège au programme.N'oubliez pas que la version 3
exec
est une fonction!utilisez donc toujours
exec(mystring)
au lieu deexec mystring
.la source
eval()
est juste pour les expressions, tandis queeval('x+1')
fonctionne,eval('x=1')
ne fonctionnera pas par exemple. Dans ce cas, il vaut mieux l'utiliserexec
, ou encore mieux: essayez de trouver une meilleure solution :)la source
Éviter
exec
eteval
Utilisation de
exec
eteval
en Python est très mal vu.Il existe de meilleures alternatives
De la réponse du haut (accent sur le mien):
Des alternatives à exec / eval?
Ce n'est pas idiomatique
De http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (accent sur le mien)
C'est dangereux
Sur http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (c'est moi qui souligne)
C'est difficile à lire et à comprendre
De http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (c'est moi qui souligne):
la source
cfg.yaml
):,reldir : ../my/dir/
etreldir = 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 doncreldir : os.path.join('..','my','dir')
dans le fichier de configuration. Mais cela ne faitreldir
qu'être cette chaîne littérale, non évaluée, donc je ne peux pas ouvrir un fichier dansreldir
. Avez-vous une suggestion?Vous effectuez l'exécution de code à l'aide de exec, comme avec la session IDLE suivante:
la source
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:
la source
Utilisez eval .
la source
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())
la source
Découvrez eval :
la source
J'ai essayé pas mal de choses, mais la seule chose qui fonctionnait était la suivante:
production:
10
la source
La solution la plus logique serait d'utiliser la fonction intégrée eval () . Une autre solution consiste à écrire cette chaîne dans un fichier python temporaire et à l'exécuter.
la source
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é
donc customerName = "jj" exécuterait apply_address_filter à partir du fichier customer_filters \ jj_filter.py
la source