Vale la pena señalar que para el problema específico en cuestión, hay varias alternativas para usar eval
:
Lo más simple, como se señaló, es usar setattr
:
def __init__(self):
for name in attsToStore:
setattr(self, name, None)
Un enfoque menos obvio es actualizar el objeto del __dict__
objeto directamente. Si todo lo que quiere hacer es inicializar los atributos None
, entonces esto es menos sencillo que lo anterior. Pero considera esto:
def __init__(self, **kwargs):
for name in self.attsToStore:
self.__dict__[name] = kwargs.get(name, None)
Esto le permite pasar argumentos de palabras clave al constructor, por ejemplo:
s = Song(name='History', artist='The Verve')
También le permite hacer su uso locals()
más explícito, por ejemplo:
s = Song(**locals())
... y, si realmente desea asignar None
a los atributos cuyos nombres se encuentran en locals()
:
s = Song(**dict([(k, None) for k in locals().keys()]))
Otro enfoque para proporcionar un objeto con valores predeterminados para una lista de atributos es definir el __getattr__
método de la clase :
def __getattr__(self, name):
if name in self.attsToStore:
return None
raise NameError, name
Este método recibe una llamada cuando el atributo nombrado no se encuentra de la manera normal. Este enfoque es algo menos directo que simplemente establecer los atributos en el constructor o actualizar el __dict__
, pero tiene el mérito de no crear realmente el atributo a menos que exista, lo que puede reducir sustancialmente el uso de memoria de la clase.
El punto de todo esto: hay muchas razones, en general, para evitar eval
: el problema de seguridad de ejecutar código que no controlas, el problema práctico de código que no puedes depurar, etc. Pero una razón aún más importante es que generalmente no necesitas usarlo. Python expone gran parte de sus mecanismos internos al programador que rara vez realmente necesita escribir código que escriba código.
exec/eval
y aún no lo sabíasetattr
?