Warto zauważyć, że w przypadku konkretnego problemu istnieje kilka alternatyw do użycia eval
:
Najprostszym, jak wspomniano, jest użycie setattr
:
def __init__(self):
for name in attsToStore:
setattr(self, name, None)
Mniej oczywistym podejściem jest bezpośrednia aktualizacja obiektu __dict__
obiektu. Jeśli wszystko, co chcesz zrobić, to zainicjować atrybuty None
, jest to mniej proste niż powyższe. Ale rozważ to:
def __init__(self, **kwargs):
for name in self.attsToStore:
self.__dict__[name] = kwargs.get(name, None)
Pozwala to na przekazanie argumentów słów kluczowych do konstruktora, np .:
s = Song(name='History', artist='The Verve')
Pozwala także na locals()
bardziej jednoznaczne użycie , np .:
s = Song(**locals())
... a jeśli naprawdę chcesz przypisać None
do atrybutów, których nazwy znajdują się w locals()
:
s = Song(**dict([(k, None) for k in locals().keys()]))
Innym podejściem do dostarczenia obiektowi wartości domyślnych dla listy atrybutów jest zdefiniowanie metody klasy __getattr__
:
def __getattr__(self, name):
if name in self.attsToStore:
return None
raise NameError, name
Ta metoda jest wywoływana, gdy nazwany atrybut nie zostanie znaleziony w normalny sposób. To podejście jest nieco mniej proste niż po prostu ustawienie atrybutów w konstruktorze lub zaktualizowanie pliku__dict__
, ale ma tę zaletę, że nie tworzy atrybutu, chyba że istnieje, co może znacznie zmniejszyć użycie pamięci klasy.
W tym wszystkim chodzi o to, że istnieje wiele powodów, których należy unikać eval
- problem bezpieczeństwa związany z wykonywaniem kodu, którego nie kontrolujesz, praktyczny problem kodu, którego nie możesz debugować itp. Ale jeszcze ważniejszy powód polega na tym, że generalnie nie musisz go używać. Python udostępnia programiście tyle swoich wewnętrznych mechanizmów, że rzadko trzeba pisać kod, który pisze kod.
exec/eval
i nadal nie wiedziałeśsetattr
?