Vale ressaltar que, para o problema específico em questão, existem várias alternativas ao uso eval
:
O mais simples, como observado, está usando setattr
:
def __init__(self):
for name in attsToStore:
setattr(self, name, None)
Uma abordagem menos óbvia é atualizar o objeto do __dict__
objeto diretamente. Se tudo o que você deseja fazer é inicializar os atributos None
, isso é menos direto do que o descrito acima. Mas considere isso:
def __init__(self, **kwargs):
for name in self.attsToStore:
self.__dict__[name] = kwargs.get(name, None)
Isso permite que você passe argumentos de palavras-chave para o construtor, por exemplo:
s = Song(name='History', artist='The Verve')
Também permite que você use locals()
mais explícito, por exemplo:
s = Song(**locals())
... e, se você realmente deseja atribuir None
aos atributos cujos nomes são encontrados em locals()
:
s = Song(**dict([(k, None) for k in locals().keys()]))
Outra abordagem para fornecer um objeto com valores padrão para uma lista de atributos é definir o __getattr__
método da classe :
def __getattr__(self, name):
if name in self.attsToStore:
return None
raise NameError, name
Este método é chamado quando o atributo nomeado não é encontrado da maneira normal. Essa abordagem é um pouco menos direta do que simplesmente definir os atributos no construtor ou atualizar o__dict__
, mas tem o mérito de não criar o atributo, a menos que ele exista, o que pode reduzir substancialmente o uso de memória da classe.
O ponto de tudo isso: em geral, existem muitas razões para evitar eval
- o problema de segurança da execução de código que você não controla, o problema prático de código que você não pode depurar etc. etc. Mas uma razão ainda mais importante é que geralmente você não precisa usá-lo. O Python expõe tanto de seus mecanismos internos ao programador que você raramente precisa escrever um código que escreva código.
exec/eval
e ainda não sabiasetattr
?