Почему использование eval - плохая практика?
34384 просмотра
8 ответа
Я использую следующий класс, чтобы легко хранить данные моих песен.
class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
exec 'self.%s=None'%(att.lower()) in locals()
def setDetail(self, key, val):
if key in self.attsToStore:
exec 'self.%s=val'%(key.lower()) in locals()
Я чувствую, что это гораздо более расширяемо, чем выписывание if/else
блока. Тем не менее, eval
кажется, считается плохой практикой и небезопасно использовать. Если да, может кто-нибудь объяснить мне, почему и показать мне лучший способ определения вышеупомянутого класса?
Ответы (8)
178 плюса
Да, использование eval - плохая практика. Просто назвать несколько причин:
- Почти всегда есть лучший способ сделать это
- Очень опасно и небезопасно
- Затрудняет отладку
- Медленный
В вашем случае вы можете использовать setattr вместо:
class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
setattr(self, att.lower(), None)
def setDetail(self, key, val):
if key in self.attsToStore:
setattr(self, key.lower(), val)
РЕДАКТИРОВАТЬ:
В некоторых случаях вы должны использовать eval или exec. Но они редки. Использование eval в вашем случае наверняка плохая практика. Я подчеркиваю плохую практику, потому что eval и exec часто используются не в том месте.
РЕДАКТИРОВАТЬ 2:
Похоже, что некоторые не согласны с тем, что eval является «очень опасным и небезопасным» в случае с OP. Это может быть верно для этого конкретного случая, но не в целом. Вопрос был общим, и причины, которые я перечислил, верны и для общего случая.
РЕДАКТИРОВАТЬ 3: Изменение порядка пунктов 1 и 4
Автор: Nadia Alramli Размещён: 02.12.2009 01:3729 плюса
Использование eval
слабое, не совсем плохая практика.
Это нарушает «Фундаментальный принцип программного обеспечения». Ваш источник не является общей суммой исполняемого файла. Помимо вашего источника, есть и аргументы
eval
, которые должны быть четко поняты. По этой причине это инструмент последней инстанции.Обычно это признак бездумного замысла. Там редко бывают веские причины для динамического исходного кода, созданного на лету. Почти все может быть сделано с делегированием и другими методами проектирования ОО.
Это приводит к относительно медленной на лету компиляции небольших фрагментов кода. Накладные расходы, которых можно избежать, используя лучшие шаблоны проектирования.
В качестве сноски, в руках невменяемых социопатов, это может не сработать. Однако, когда сталкиваешься с ненормальными социопатическими пользователями или администраторами, лучше вообще не давать им интерпретируемый Python. В руках действительно зла, Python может быть ответственностью; eval
не увеличивает риск вообще.
22 плюса
В этом случае да. Вместо
exec 'self.Foo=val'
Вы должны использовать встроенную функцию setattr
:
setattr(self, 'Foo', val)
Автор: Josh Lee
Размещён: 02.12.2009 01:38
13 плюса
Да, это:
Взломать с помощью Python:
>>> eval(input())
"__import__('os').listdir('.')"
...........
........... #dir listing
...........
В приведенном ниже коде перечислены все задачи, выполняемые на компьютере под управлением Windows.
>>> eval(input())
"__import__('subprocess').Popen(['tasklist'],stdout=__import__('subprocess').PIPE).communicate()[0]"
В Linux:
>>> eval(input())
"__import__('subprocess').Popen(['ps', 'aux'],stdout=__import__('subprocess').PIPE).communicate()[0]"
Автор: Hackaholic
Размещён: 06.05.2016 08:41
6 плюса
Стоит отметить, что для конкретной проблемы есть несколько альтернатив использования eval
:
Самым простым, как уже отмечалось, является использование setattr
:
def __init__(self):
for name in attsToStore:
setattr(self, name, None)
Менее очевидный подход - __dict__
непосредственное обновление объекта. Если все, что вы хотите сделать, это инициализировать атрибуты None
, то это не так просто, как указано выше. Но учтите это:
def __init__(self, **kwargs):
for name in self.attsToStore:
self.__dict__[name] = kwargs.get(name, None)
Это позволяет передавать аргументы ключевого слова в конструктор, например:
s = Song(name='History', artist='The Verve')
Это также позволяет сделать использование locals()
более явным, например:
s = Song(**locals())
... и, если вы действительно хотите назначить None
атрибуты, имена которых находятся в locals()
:
s = Song(**dict([(k, None) for k in locals().keys()]))
Другой подход к предоставлению объекта со значениями по умолчанию для списка атрибутов состоит в определении __getattr__
метода класса :
def __getattr__(self, name):
if name in self.attsToStore:
return None
raise NameError, name
Этот метод вызывается, когда именованный атрибут не найден обычным способом. Этот подход несколько менее прост, чем простая установка атрибутов в конструкторе или обновление __dict__
, но он имеет преимущество в том, что фактически не создает атрибут, если он не существует, что может существенно уменьшить использование памяти классом.
Суть всего этого: в общем, есть много причин, которых следует избегать eval
- проблема безопасности выполнения кода, который вы не контролируете, практическая проблема кода, который вы не можете отлаживать, и т. Д. Но еще более важная причина это вообще, вам не нужно его использовать. Python предоставляет так много своих внутренних механизмов программисту, что вам редко нужно писать код, который пишет код.
5 плюса
Другие пользователи указали, как можно изменить ваш код, чтобы не зависеть от него eval
; Я предложу законный вариант использования eval
, который встречается даже в CPython: тестирование .
Вот один пример, который я нашел, test_unary.py
где тест на то, (+|-|~)b'a'
поднимает ли TypeError
:
def test_bad_types(self):
for op in '+', '-', '~':
self.assertRaises(TypeError, eval, op + "b'a'")
self.assertRaises(TypeError, eval, op + "'a'")
Использование здесь явно не плохая практика; Вы определяете вход и просто наблюдаете за поведением. eval
удобно для тестирования.
Посмотрите на этот поиске для eval
, исполненного на репозитории CPython; тестирование с помощью eval активно используется.
2 плюса
Когда eval()
используется для обработки предоставленного пользователем ввода, вы разрешаете пользователю Drop-to-REPL предоставлять что-то вроде этого:
"__import__('code').InteractiveConsole(locals=globals()).interact()"
Вам это может сойти с рук, но обычно вам не нужны векторы для выполнения произвольного кода в ваших приложениях.
Автор: moooeeeep Размещён: 29.05.2018 09:470 плюса
В дополнение к @Nadia Alramli ответ, так как я новичок в Python , и хотел , чтобы проверить , как использование eval
будет влиять на тайминги , я попробовал небольшую программу и ниже были наблюдения:
#Difference while using print() with eval() and w/o eval() to print an int = 0.528969s per 100000 evals()
from datetime import datetime
def strOfNos():
s = []
for x in range(100000):
s.append(str(x))
return s
strOfNos()
print(datetime.now())
for x in strOfNos():
print(x) #print(eval(x))
print(datetime.now())
#when using eval(int)
#2018-10-29 12:36:08.206022
#2018-10-29 12:36:10.407911
#diff = 2.201889 s
#when using int only
#2018-10-29 12:37:50.022753
#2018-10-29 12:37:51.090045
#diff = 1.67292
Автор: Lokeshwar Tailor
Размещён: 29.10.2018 07:26
Вопросы из категории :
- python Обработка XML в Python
- python Как я могу использовать Python itertools.groupby ()?
- python Python: На какой ОС я работаю?
- python Как я могу создать непосредственно исполняемое кроссплатформенное приложение с графическим интерфейсом на Python?
- python Вызов функции модуля с использованием его имени (строки)
- python Звук Питона («Колокол»)
- python Regex и unicode
- python Создать зашифрованный ZIP-файл в Python
- python Создайте базовый итератор Python
- python Функция транспонирования / распаковки (обратная сторона zip)?
- eval Как я могу оценить выражение C # динамически?
- eval Когда eval () в JavaScript не является злом?
- eval Когда Eval зло в PHP?
- eval Почему для eval в JavaScript нужны скобки для оценки данных JSON?
- eval Можно ли выполнить строку в MySQL?
- eval Выполнение кода Python, содержащегося в строке
- eval Правильная обработка пробелов и кавычек в завершении bash
- eval Оценить выражение в виде строки
- eval Почему использование eval - плохая практика?
- eval Eval скрипт для свойства идентификатора элемента управления на стороне сервера?