В книге, которую я читаю на Python, он продолжает использовать код eval(input('blah'))
Я прочитал документацию, и я понимаю это, но я все еще не вижу, как это меняет input()
функцию.
Что оно делает? Может кто-нибудь объяснить?
В книге, которую я читаю на Python, он продолжает использовать код eval(input('blah'))
Я прочитал документацию, и я понимаю это, но я все еще не вижу, как это меняет input()
функцию.
Что оно делает? Может кто-нибудь объяснить?
Ответы:
Функция eval позволяет программе Python запускать код Python внутри себя.
Пример eval (интерактивная оболочка):
>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1
eval()
также может использоваться для выполнения высокодинамичного кода, но вы должны полностью осознавать риски безопасности и производительности перед его использованием.
eval
и не может делать то, что делает eval
.
eval
кроме того, что он небезопасен, он не может запускать целые программы, как это делает codepad, потому что он может вычислять только одно выражение.
eval()
интерпретирует строку как код Причина, по которой так много людей предупредили вас об этом, заключается в том, что пользователь может использовать это в качестве опции для запуска кода на компьютере. Если у вас есть eval(input())
и os
импортированы, человек может ввести, input()
os.system('rm -R *')
который удалит все ваши файлы в вашем домашнем каталоге. (Предполагая, что у вас есть система Unix). Использование eval()
это дыра в безопасности. Если вам нужно преобразовать строки в другие форматы, попробуйте использовать такие вещи, как int()
.
eval
с input()
является дырой в безопасности. Не помещайте input()
в утверждение eval, и все будет в порядке.
eval
же как и проблема безопасности во многих случаях.
input
как обычно получает данные из консоли, пользователь может просто выйти из программы и в rm -R *
любом случае набрать ...
Здесь много хороших ответов, но ни один не описывает их использование 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]
В 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
в выражение и интерпретируемой. Обычно это считается плохой практикой.
input
означает, что raw_input
сделал в 2.x.
Возможно, вводящий в заблуждение пример чтения строки и ее интерпретации.
Попробуйте eval(input())
и введите "1+1"
- это должно напечатать 2
. Eval оценивает выражения.
eval()
оценивает переданную строку как выражение Python и возвращает результат. Например, eval("1 + 1")
интерпретирует и выполняет выражение "1 + 1"
и возвращает результат (2).
Одна из причин, по которой вы можете быть сбиты с толку, заключается в том, что приведенный вами код включает в себя определенный уровень косвенности. Внутренний вызов функции (input) выполняется первым, поэтому пользователь видит подсказку «blah». Давайте представим, что они отвечают «1 + 1» (кавычки добавлены для ясности, не вводите их при запуске вашей программы), функция ввода возвращает эту строку, которая затем передается внешней функции (eval), которая интерпретирует строку и возвращает результат (2).
Узнайте больше о Eval здесь .
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.
Одним из полезных применений 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'}
eval
делает?
Я опоздал, чтобы ответить на этот вопрос, но, кажется, никто не дает четкого ответа на вопрос.
Если пользователь введет числовое значение, 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()
или float()
следует использовать вместо eval()
этого.
>>> float(input('Enter a number: '))
Enter a number: 3.14
3.14
Другой вариант, если вы хотите ограничить строку оценки простыми литералами, это использовать 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.
ast.literal_eval
не поддерживает операторов, вопреки вашему '1+1'
примеру. Тем не менее, он поддерживает списки, числа, строки и т. Д., И поэтому является хорошей альтернативой для обычных eval
случаев использования.