345 votes

Que fait la fonction eval() de Python ?

Dans le livre que je suis en train de lire sur Python, on continue à utiliser le code eval(input('blah'))

J'ai lu la documentation, et je la comprends, mais je ne vois toujours pas comment cela change la input() fonction.

Que fait-il ? Quelqu'un peut-il l'expliquer ?

4 votes

La fonction Eval essaie d'exécuter et d'interpréter la chaîne de caractères (argument) qui lui est passée comme un code python. x=1 print (eval('x+1')) La sortie du code ci-dessus sera 2. L'inconvénient d'une telle approche est que l'utilisateur est libre d'écrire du code, ce qui peut entraîner des conditions difficiles, bien que vous puissiez restreindre l'accès des utilisateurs à de nombreuses variables et méthodes en passant des paramètres globaux et locaux dans la fonction eval.

312voto

BYS2 Points 990

La fonction eval permet à un programme Python d'exécuter du code Python en son sein.

Exemple d'évaluation (shell interactif) :

>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1

28 votes

Haha, c'était un exemple trivial, mais vous pourriez laisser l'utilisateur taper une commande arbitraire et la faire exécuter par python. Vous pourriez donc demander à l'utilisateur de taper une chaîne de commande et faire en sorte que python l'exécute en tant que code. Donc par exemple : eval("__import__('os').remove('file')").

67 votes

Il vous semblera inutile jusqu'à ce que vous en trouviez le besoin. Il est utilisé sur des sites comme codepad.org pour vous permettre d'exécuter des scripts dans un environnement de test. eval() peut également être utilisé pour exécuter du code hautement dynamique, mais vous devez être pleinement conscient des risques en matière de sécurité et de performances avant de l'utiliser.

8 votes

@GeorgeCummins, le codepad.org n'utilise pas eval Il ne pourrait pas non plus faire ce qu'il fait avec eval .

182voto

CoffeeRain Points 1838

eval() interprète une chaîne de caractères comme un code. La raison pour laquelle tant de personnes vous ont mis en garde contre cette utilisation est qu'un utilisateur peut l'utiliser comme une option pour exécuter du code sur l'ordinateur. Si vous avez eval(input()) et os importé, une personne pourrait taper dans input() os.system('rm -R *') ce qui supprimerait tous vos fichiers dans votre répertoire personnel. (En supposant que vous ayez un système unix). Utilisation de eval() est une faille de sécurité. Si vous avez besoin de convertir des chaînes de caractères dans d'autres formats, essayez d'utiliser des choses qui font cela, comme int() .

19 votes

Vous voulez dire en utilisant eval avec input() est une faille de sécurité. Ne mettez pas input() dans une déclaration eval et tout ira bien.

29 votes

@Rohmer, les données non sécurisées peuvent provenir de partout : requêtes web, champs de saisie de formulaires, lecture de fichiers, ... pas seulement de l'entrée console. Même si vous écrivez les fichiers vous-même, ils peuvent toujours contenir des données provenant d'une source non fiable. Ainsi, eval est un problème de sécurité dans de nombreux cas.

4 votes

Depuis input prend généralement ses données depuis la console, l'utilisateur pourrait simplement quitter le programme et taper rm -R * de toute façon...

73voto

Grr Points 6929

Beaucoup de bonnes réponses ici, mais aucune ne décrit l'utilisation de eval() dans le contexte de son globals et locals kwargs, c'est-à-dire eval(expression, globals=None, locals=None) (voir les documents relatifs à eval ici ).

Ceux-ci peuvent être utilisés pour limiter les fonctions qui sont disponibles par le biais de l'interface utilisateur. eval fonction. Par exemple, si vous chargez un nouvel interpréteur python, la fonction locals() et globals() seront les mêmes et ressembleront à quelque chose comme ça :

>>>globals()
{'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__doc__': None,
 '__spec__': None, '__builtins__': <module 'builtins' (built-in)>,
 '__package__': None, '__name__': '__main__'}

Il y a certainement des fonctions au sein de la builtins module qui peut causer des dommages importants à un système. Mais il est possible de bloquer tout ce que l'on ne veut pas rendre disponible. Prenons un exemple. Disons que nous voulons construire une liste pour représenter un domaine des cœurs disponibles sur un système. Dans mon cas, je dispose de 8 cœurs et je voudrais donc une liste [1, 8] .

>>>from os import cpu_count
>>>eval('[1, cpu_count()]')
[1, 8]

De même, tous les __builtins__ est disponible.

>>>eval('abs(-1)')
1

Ok. Nous voyons donc une fonction que nous voulons exposer et un exemple d'une méthode (parmi de nombreuses autres qui peuvent être beaucoup plus complexes) que nous ne voulons pas exposer. Alors bloquons tout.

>>>eval('[1, cpu_count()]', {'__builtins__':None}, {})
TypeError: 'NoneType' object is not subscriptable

Nous avons effectivement bloqué toutes les __builtins__ et en tant que tel, il a apporté un niveau de protection dans notre système. À ce stade, nous pouvons commencer à réintégrer les fonctions que nous voulons exposer.

>>>from os import cpu_count
>>>exposed_methods = {'cpu_count': cpu_count}
>>>eval('cpu_count()', {'__builtins__':None}, exposed_methods)
8
>>>eval('abs(cpu_count())', {'__builtins__':None}, exposed_methods)
TypeError: 'NoneType' object is not subscriptable

Maintenant, nous avons le cpu_count fonction disponible tout en bloquant tout ce que nous ne voulons pas. À mon avis, ceci est super puissant et clairement de la portée des autres réponses, pas une mise en œuvre commune. Il y a de nombreuses utilisations pour quelque chose comme ça et tant que c'est traité correctement, je pense personnellement que eval peut être utilisé en toute sécurité et à bon escient.

N.B.

Une autre chose qui est cool à propos de ces kwargs c'est que vous pouvez commencer à utiliser des raccourcis pour votre code. Disons que vous utilisez eval dans le cadre d'un pipeline pour exécuter un texte importé. Le texte n'a pas besoin d'avoir un code exact, il peut suivre un certain format de fichier modèle, et toujours exécuter ce que vous voulez. Par exemple :

>>>from os import cpu_count
>>>eval('[1,cores]', {'__builtins__': None}, {'cores': cpu_count()})
[1, 8]

29voto

zeekay Points 22640

En Python 2.x input(...) est équivalent à eval(raw_input(...)) dans Python 3.x raw_input a été renommé input ce qui, je le soupçonne, est à l'origine de votre confusion (vous avez probablement consulté la documentation de l'application input dans Python 2.x). En outre, eval(input(...)) fonctionnerait sans problème dans Python 3.x, mais soulèverait un problème de type TypeError dans Python 2.

Dans ce cas eval est utilisé pour contraindre la chaîne retournée par input en une expression et interprété. En général, cela est considéré comme une mauvaise pratique.

0 votes

Ou bien il s'agit d'un livre sur Python 3.x, où input signifie que raw_input a fait dans 2.x.

1 votes

Oui, j'y ai pensé après avoir écrit ma réponse initiale, et c'est clairement le cas.

7voto

Rubal Points 846

eval() comme son nom l'indique, évalue l'argument passé.

raw_input() est maintenant input() dans les versions 3.x de python. Ainsi, l'exemple le plus couramment rencontré pour l'utilisation de eval() est son utilisation pour fournir la fonctionnalité que input() fourni dans la version 2.x de python. raw_input renvoie les données saisies par l'utilisateur sous forme de chaîne, tandis que input évalue la valeur des données saisies et la renvoie.

eval(input("bla bla")) reproduit donc la fonctionnalité de input() en 2.x, c'est-à-dire l'évaluation des données entrées par l'utilisateur.

En bref : eval() évalue les arguments qui lui sont passés et donc eval('1 + 1') retourné 2.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X