Мне удалось «починить» его, удалив каталог .idea
и снова открыв проект. Каталог .idea
обычно не фиксируется в git, но я полагаю, что копирование каталога делает недействительными структуры каталогов в файлах в каталоге .idea.
Вся ошибка легко воспроизводится, когда вы нажимаете File
> Re-import Gradle project
.
Да, использование 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 переупорядочены
Когда eval()
используется для обработки предоставленного пользователем ввода, вы разрешаете пользователю Drop-to-REPL , предоставляя что-то вроде этого:
"__import__('code').InteractiveConsole(locals=globals()).interact()"
Вы можете уйти с этим, но обычно вам не нужны векторы для выполнения произвольного кода в ваших приложениях.
Использование eval
является слабым, а не явно плохой практикой.
Это нарушает «Основополагающие принципы программного обеспечения». Ваш источник - это не совокупность исполняемых файлов. Помимо вашего источника, есть аргументы eval
, которые необходимо четко понимать. По этой причине это крайняя мера.
Обычно это признак бездумного замысла. Редко есть веская причина для динамического исходного кода, создаваемого «на лету». С делегированием и другими техниками объектно-ориентированного проектирования можно сделать практически все.
Это приводит к относительно медленной компиляции небольших фрагментов кода на лету. Накладные расходы, которых можно избежать, используя более совершенные шаблоны проектирования.
В качестве примечания, в руках психопатов это может не сработать. Однако при столкновении с невменяемыми пользователями или администраторами-социопатами лучше вообще не давать им интерпретируемый Python. В руках истинного зла Python может стать помехой; eval
совсем не увеличивает риск.
eval
совсем не увеличивает риск. когда вы сталкиваетесь с невменяемыми пользователями или администраторами-социопатами, лучше вообще не давать им интерпретируемый Python. В руках истинного зла Python может стать помехой; eval
совсем не увеличивает риск. В данном случае да. Вместо
exec 'self.Foo=val'
вы должны использовать встроенную функцию setattr
:
setattr(self, 'Foo', val)
Стоит отметить, что для конкретной рассматриваемой проблемы существует несколько альтернатив использованию 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
- проблема безопасности выполнения кода, который вы не контролируете, практическая проблема кода, который вы не можете отладить. и т. д. Но еще более важная причина в том, что, как правило, вам не нужно его использовать.