Вопрос-Ответ

Why is using 'eval' a bad practice?

Почему использование 'eval' является плохой практикой?

Я использую следующий класс для удобного хранения данных моих песен.

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 это небезопасно. Так ли это? Каков риск? Как я могу решить основную проблему в моем классе (динамически устанавливая атрибуты self), не подвергаясь такому риску?

Переведено автоматически
Ответ 1

Да, использование eval - плохая практика. Просто назову несколько причин:


  1. Почти всегда есть лучший способ сделать это

  2. Очень опасно и небезопасно

  3. Затрудняет отладку

  4. Медленно

В вашем случае вы можете использовать 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 часто используются не в том месте.

Отвечаю на комментарии:

Похоже, некоторые не согласны с тем, что eval "очень опасно и небезопасно" в случае OP. Это может быть верно для данного конкретного случая, но не в целом. Вопрос был общим, и перечисленные мной причины справедливы и для общего случая.

Ответ 2

Использование eval слабое, а не явно плохая практика.


  1. Это нарушает "Фундаментальный принцип программного обеспечения". Ваш исходный код не является общей суммой исполняемого файла. В дополнение к вашему исходному коду есть аргументы для eval, которые должны быть четко поняты. По этой причине это инструмент последней инстанции.


  2. Обычно это признак бездумного проектирования. Редко бывает веская причина для динамического исходного кода, создаваемого "на лету". Почти все можно сделать с помощью делегирования и других методов OO-проектирования.


  3. Это приводит к относительно медленной компиляции небольших фрагментов кода "на лету". Накладные расходы, которых можно избежать, используя лучшие шаблоны проектирования.


В качестве примечания, в руках невменяемых социопатов это может плохо сработать. Однако, когда сталкиваешься с невменяемыми пользователями-социопатами или администраторами, лучше вообще не давать им интерпретируемый Python. В руках истинного зла Python может стать помехой; eval совсем не увеличивает риск.

Ответ 3

Да, это так:

Взлом с помощью 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]"
Ответ 4

В данном случае да. Вместо

exec 'self.Foo=val'

вам следует использовать встроенную функцию setattr:

setattr(self, 'Foo', val)
python