Что делает Python eval()?

В книге, которую я читаю на Python, она продолжает использовать код eval(input('blah'))

Я прочитал документацию, и я это понимаю, но я до сих пор не вижу, как она меняет функцию input().

Что он делает? Может кто-нибудь объяснить?

Ответ 1

Функция eval позволяет программе Python запускать код Python внутри себя.

Пример eval (интерактивная оболочка):

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

Ответ 2

eval() интерпретирует строку как код. Причина, по которой так много людей предупреждала вас об использовании этого, заключается в том, что пользователь может использовать это как вариант для запуска кода на компьютере. Если вы импортировали eval(input()) и os, человек может ввести input() os.system('rm -R *'), который удалит все ваши файлы в вашем домашнем каталоге. (Предположим, что у вас есть система unix). Использование eval() - это дыра в безопасности. Если вам нужно преобразовать строки в другие форматы, попробуйте использовать те вещи, которые делают это, например int().

Ответ 3

Много хороших ответов здесь, но никто не описывает использование eval() в контексте его globals и locals kwargs, т.е. eval(expression, globals=None, locals=None) (см документацию для eval здесь).

Их можно использовать для ограничения методов, доступных через метод eval. Например, если вы загрузите новый интерпретатор python, locals() и globals() будут одинаковыми и будут выглядеть примерно так:

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

Во builtins модуле, безусловно, есть методы, которые могут нанести значительный ущерб системе. Но можно заблокировать все, что мы не хотим, доступное. Давайте возьмем пример. Допустим, мы хотим создать список, представляющий домен доступных ядер в системе. Для меня у меня есть 8 ядер, поэтому я бы хотел список [1, 8].

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

Также доступны все __builtins__.

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

Хорошо. Таким образом, мы видим один метод, который мы хотим раскрыть, и пример одного (из многих, который может быть гораздо более сложного) метода, который мы не хотим раскрывать. Итак, давайте заблокируем все.

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

Мы эффективно заблокировали все методы __builtins__ и, таким образом, повысили уровень защиты нашей системы. На этом этапе мы можем начать добавлять методы, которые мы хотим раскрыть.

>>>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

Теперь у нас есть метод cpu_count который блокирует все, что нам не нужно. На мой взгляд, это супер мощный и явно из сферы других ответов, а не общего осуществления. Существует множество вариантов использования чего-то подобного, и до тех пор, пока оно обрабатывается правильно, я лично чувствую, что eval можно безопасно использовать для получения высокой стоимости.

NB

Что еще хорошо в этих kwargs это то, что вы можете начать использовать сокращение для своего кода. Допустим, вы используете eval как часть конвейера для выполнения некоторого импортированного текста. Текст не обязательно должен содержать точный код, он может соответствовать какому-либо формату файла шаблона и при этом выполнять все, что вы захотите. Например:

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

Ответ 4

В Python 2.x input(...) эквивалентно eval(raw_input(...)), в Python 3.x raw_input было переименовано input, которое, как я подозреваю, привело к вашей путанице (вы, вероятно, смотрели документацию для input в Python 2.x). Кроме того, eval(input(...)) отлично работает в Python 3.x, но поднимет TypeError в Python 2.

В этом случае eval используется для принуждения строки, возвращаемой из input, в выражение и интерпретируется. Как правило, это считается плохой практикой.

Ответ 5

eval() оценивает переданную строку как выражение Python и возвращает результат. Например, eval("1 + 1") интерпретирует и выполняет выражение "1 + 1" и возвращает результат (2).

Одна из причин, по которой вы можете быть сбиты с толку, заключается в том, что приведенный вами код включает в себя определенный уровень косвенности. Внутренний вызов функции (input) выполняется первым, поэтому пользователь видит подсказку "blah". Давайте представим, что они отвечают "1 + 1" (кавычки добавлены для ясности, не вводите их при запуске вашей программы), функция ввода возвращает эту строку, которая затем передается внешней функции (eval), которая интерпретирует строку и возвращает результат (2).

Узнайте больше о Eval здесь.

Ответ 6

Может быть, вводящий в заблуждение пример чтения строки и ее интерпретации.

Попробуйте eval(input()) и введите "1+1" - это должно напечатать 2. Eval оценивает выражения.

Ответ 7

Одним из полезных приложений eval() является оценка выражений Python из строки. Например загрузить из файла строковое представление словаря:

running_params = {"Greeting":"Hello "}
fout = open("params.dat",'w')
fout.write(repr(running_params))
fout.close()

Прочитайте это как переменную и отредактируйте это:

fin = open("params.dat",'r')
diction=eval(fin.read())
diction["Greeting"]+="world"
fin.close()
print diction

Выход:

{'Greeting': 'Hello world'}

Ответ 8

eval(), как следует из названия, оценивает переданный аргумент.

raw_input() теперь является input() в версиях Python 3.x. Таким образом, наиболее часто встречающимся примером использования eval() является его использование для предоставления функциональных возможностей, которые input() предоставляет в версии 2.x python. raw_input возвращает введенные пользователем данные в виде строки, а input оценивает значение введенных данных и возвращает их.

eval(input("bla bla")) таким образом, копирует функциональность input() в 2.x, то есть оценки введенных пользователем данных.

Вкратце: eval() оценивает переданные ему аргументы и, следовательно, eval('1 + 1') возвращает 2.

Ответ 9

Я опоздал, чтобы ответить на этот вопрос, но, кажется, никто не дает четкого ответа на вопрос.

Если пользователь вводит числовое значение, input() возвращает строку.

>>> input('Enter a number: ')
Enter a number: 3
>>> '3'
>>> input('Enter a number: ')
Enter a number: 1+1
'1+1'

Таким образом, eval() оценивает возвращаемое значение (или выражение), которое является строкой, и возвращает целое число/число с плавающей запятой.

>>> eval(input('Enter a number: '))
Enter a number: 1+1
2
>>> 
>>> eval(input('Enter a number: '))
Enter a number: 3.14
3.14

Конечно, это плохая практика. int() этом случае вместо eval() следует использовать int() или float().

>>> float(input('Enter a number: '))
Enter a number: 3.14
3.14

Ответ 10

Другой вариант, если вы хотите ограничить строку оценки простыми литералами, это использовать ast.literal_eval(). Некоторые примеры:

import ast

# print(ast.literal_eval(''))          # SyntaxError: unexpected EOF while parsing
# print(ast.literal_eval('a'))         # ValueError: malformed node or string
# print(ast.literal_eval('import os')) # SyntaxError: invalid syntax
# print(ast.literal_eval('1+1'))       # 2: but only works due to a quirk in parser
# print(ast.literal_eval('1*1'))       # ValueError: malformed node or string
print(ast.literal_eval("{'a':1}"))     # {'a':1}

Из документов:

Безопасно оцените узел выражения или строку, содержащую литерал Python или отображение контейнера. Предоставленная строка или узел могут состоять только из следующих литеральных структур Python: строк, байтов, чисел, кортежей, списков, диктов, наборов, логических значений и None.

Это можно использовать для безопасной оценки строк, содержащих значения Python из ненадежных источников, без необходимости разбора значений самостоятельно. Он не способен вычислять произвольно сложные выражения, например, с использованием операторов или индексации.

Что касается того, почему это так ограничено, из списка рассылки:

Разрешение выражений операторов с литералами возможно, но гораздо сложнее, чем текущая реализация. Простая реализация небезопасна: вы можете без усилий вызывать практически неограниченное использование процессора и памяти (попробуйте "9 ** 9 ** 9" или "[None] * 9 ** 9").

Что касается полезности, то эта функция полезна для "чтения" литеральных значений и контейнеров в виде строк с помощью repr(). Это может, например, использоваться для сериализации в формате, который похож на, но более мощный, чем JSON.

Ответ 11

eval() делает строку с целыми числами в ней математическим уравнением (все в строке воспринимается как текст, поэтому целые числа в этом случае означают числа как текст), поэтому, если какая-либо помощь нужна там, она есть.