Używam następującej klasy, aby łatwo przechowywać dane moich piosenek.
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:
exec 'self.%s=None'%(att.lower()) in locals()
def setDetail(self, key, val):
if key in self.attsToStore:
exec 'self.%s=val'%(key.lower()) in locals()
Uważam, że jest to o wiele bardziej rozszerzalne niż pisanie if/else
bloku. Jednak eval
wydaje się być uważany za złą praktykę i niebezpieczny w użyciu. Jeśli tak, czy ktoś może mi wyjaśnić dlaczego i pokazać lepszy sposób zdefiniowania powyższej klasy?
exec/eval
i nadal nie wiedziałeśsetattr
?Odpowiedzi:
Tak, używanie eval to zła praktyka. Żeby wymienić tylko kilka powodów:
W twoim przypadku możesz zamiast tego użyć setattr :
EDYTOWAĆ:
W niektórych przypadkach musisz użyć funkcji eval lub exec. Ale są rzadkie. Używanie eval w twoim przypadku jest z pewnością złą praktyką. Podkreślam złe praktyki, ponieważ eval i exec są często używane w niewłaściwym miejscu.
EDYCJA 2:
Wygląda na to, że niektórzy nie zgadzają się, że eval jest „bardzo niebezpieczny i niepewny” w przypadku OP. Może to być prawdą w tym konkretnym przypadku, ale nie ogólnie. Pytanie było ogólne, a powody, które wymieniłem, są prawdziwe również dla przypadku ogólnego.
EDYCJA 3: Zmieniono kolejność punktów 1 i 4
źródło
eval
nie mają ze sobą nic wspólnego. Aplikacja, która jest zasadniczo źle zaprojektowana, jest zasadniczo źle zaprojektowana.eval
nie jest bardziej główną przyczyną złego projektu niż dzielenie przez zero lub próba zaimportowania modułu, o którym wiadomo, że nie istnieje.eval
nie jest niepewne. Aplikacje są niezabezpieczone.calc
, a aby dodać liczby, wykonuje goprint(eval("{} + {}".format(n1, n2)))
i kończy. Teraz rozpowszechniasz ten program z jakimś systemem operacyjnym. Następnie ktoś tworzy skrypt basha, który pobiera kilka liczb z witryny giełdowej i dodaje je za pomocącalc
. Bum?Używanie
eval
jest słabe i nie jest wyraźnie złą praktyką.Narusza „Podstawową zasadę oprogramowania”. Twoje źródło nie jest sumą tego, co jest wykonywalne. Oprócz twojego źródła istnieją argumenty
eval
, które należy jasno zrozumieć. Z tego powodu jest to narzędzie ostatniej szansy.Zwykle jest to oznaka bezmyślnego projektu. Rzadko istnieje dobry powód dla dynamicznego kodu źródłowego, budowanego w locie. Prawie wszystko można zrobić za pomocą delegacji i innych technik projektowania obiektowego.
Prowadzi to do stosunkowo powolnej kompilacji małych fragmentów kodu w locie. Narzut, którego można uniknąć, stosując lepsze wzorce projektowe.
Jak przypis, w rękach obłąkanych socjopatów może się to nie udać. Jednak w konfrontacji z obłąkanymi socjopatycznymi użytkownikami lub administratorami najlepiej nie dawać im interpretowanego języka Python. W rękach naprawdę złego Python może być ciężarem;
eval
w ogóle nie zwiększa ryzyka.źródło
eval
jest to rodzaj „luki w zabezpieczeniach”. Jakby sam Python nie był tylko zbiorem interpretowanych źródeł, które każdy mógł zmodyfikować. W konfrontacji z „eval jest luką bezpieczeństwa”, można tylko założyć, że jest to luka w rękach socjopatów. Zwykli programiści po prostu modyfikują istniejące źródła Pythona i bezpośrednio powodują problemy. Nie pośrednio przezeval
magię.while True: pass
trudno byłoby posprzątać jakimś rodzajem ucieczki.eval()
, ponieważ jest to ciąg. Kodu ze „świata zewnętrznego” nie można oczyścić. Struny ze świata zewnętrznego to tylko struny. Nie wiem, o czym mówisz. Być może powinieneś podać bardziej kompletny post na blogu i link do niego tutaj.W tym przypadku tak. Zamiast
powinieneś użyć wbudowanej funkcji
setattr
:źródło
Tak to jest:
Hack używając Pythona:
Poniższy kod zawiera listę wszystkich zadań uruchomionych na komputerze z systemem Windows.
W systemie Linux:
źródło
Warto zauważyć, że w przypadku konkretnego problemu istnieje kilka alternatyw do użycia
eval
:Najprostszym, jak wspomniano, jest użycie
setattr
:Mniej oczywistym podejściem jest bezpośrednia aktualizacja obiektu
__dict__
obiektu. Jeśli wszystko, co chcesz zrobić, to zainicjować atrybutyNone
, jest to mniej proste niż powyższe. Ale rozważ to:Pozwala to na przekazanie argumentów słów kluczowych do konstruktora, np .:
Pozwala także na
locals()
bardziej jednoznaczne użycie , np .:... a jeśli naprawdę chcesz przypisać
None
do atrybutów, których nazwy znajdują się wlocals()
:Innym podejściem do dostarczenia obiektowi wartości domyślnych dla listy atrybutów jest zdefiniowanie metody klasy
__getattr__
: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.źródło
__dict__
bezpośrednio obiektu , nadaj obiektowi rzeczywisty obiekt słownika, albo przez dziedziczenie, albo jako atrybut.__setattr__
zastąpienie, co może prowadzić do nieoczekiwanych wyników.setattr()
nie ma tego problemu.Inni użytkownicy wskazywali, jak można zmienić kod, aby nie polegać na
eval
; Zaproponuję uzasadniony przypadek użyciaeval
, który można znaleźć nawet w CPythonie: testing .Oto jeden przykład, który znalazłem,
test_unary.py
gdzie test sprawdzający, czy(+|-|~)b'a'
podnosi aTypeError
:Użycie nie jest tutaj złą praktyką; definiujesz dane wejściowe i po prostu obserwujesz zachowanie.
eval
jest przydatny do testowania.Spójrz na tego wyszukiwania dla
eval
przeprowadzana jest na git repozytorium CPython; testowanie z eval jest często używane.źródło
Gdy
eval()
jest używany do przetwarzania danych wejściowych wprowadzonych przez użytkownika, umożliwiasz użytkownikowi Drop-to-REPL, podając coś takiego:Może ci się to udać, ale zwykle nie chcesz wektorów do wykonywania dowolnego kodu w swoich aplikacjach.
źródło
Oprócz odpowiedzi @Nadia Alramli, ponieważ jestem nowy w Pythonie i bardzo chciałem sprawdzić, jak użycie
eval
wpłynie na czasy , wypróbowałem mały program i poniżej były spostrzeżenia:źródło