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

Мне удалось «починить» его, удалив каталог .idea и снова открыв проект. Каталог .idea обычно не фиксируется в git, но я полагаю, что копирование каталога делает недействительными структуры каталогов в файлах в каталоге .idea.

Вся ошибка легко воспроизводится, когда вы нажимаете File> Re-import Gradle project.

125
задан martineau 24 June 2017 в 14:55
поделиться

5 ответов

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

РЕДАКТИРОВАТЬ 2:

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

РЕДАКТИРОВАТЬ 3: Пункты 1 и 4 переупорядочены

179
ответ дан 24 November 2019 в 00:59
поделиться

Когда eval() используется для обработки предоставленного пользователем ввода, вы разрешаете пользователю Drop-to-REPL , предоставляя что-то вроде этого:

"__import__('code').InteractiveConsole(locals=globals()).interact()"

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

2
ответ дан moooeeeep 24 November 2019 в 00:59
поделиться

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

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

  2. Обычно это признак бездумного замысла. Редко есть веская причина для динамического исходного кода, создаваемого «на лету». С делегированием и другими техниками объектно-ориентированного проектирования можно сделать практически все.

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

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

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

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

29
ответ дан 24 November 2019 в 00:59
поделиться

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

exec 'self.Foo=val'

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

setattr(self, 'Foo', val)
22
ответ дан 24 November 2019 в 00:59
поделиться

Стоит отметить, что для конкретной рассматриваемой проблемы существует несколько альтернатив использованию 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 - проблема безопасности выполнения кода, который вы не контролируете, практическая проблема кода, который вы не можете отладить. и т. д. Но еще более важная причина в том, что, как правило, вам не нужно его использовать.

6
ответ дан 24 November 2019 в 00:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: