Ich verwende die folgende Klasse, um Daten meiner Songs einfach zu speichern.
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()
Ich bin der Meinung, dass dies viel erweiterbarer ist als das Ausschreiben eines if/else
Blocks. Allerdings eval
scheint eine schlechte Praxis und unsicher zu verwenden , in Betracht gezogen werden. Wenn ja, kann mir jemand erklären, warum und mir einen besseren Weg zeigen, die obige Klasse zu definieren?
exec/eval
und wussten es immer noch nichtsetattr
?Antworten:
Ja, die Verwendung von eval ist eine schlechte Praxis. Um nur einige Gründe zu nennen:
In Ihrem Fall können Sie stattdessen setattr verwenden:
BEARBEITEN:
In einigen Fällen müssen Sie eval oder exec verwenden. Aber sie sind selten. Die Verwendung von eval in Ihrem Fall ist mit Sicherheit eine schlechte Praxis. Ich betone schlechte Praktiken, weil eval und exec häufig am falschen Ort verwendet werden.
EDIT 2:
Es sieht so aus, als ob einige anderer Meinung sind, dass die Bewertung im OP-Fall „sehr gefährlich und unsicher“ ist. Das mag für diesen speziellen Fall zutreffen, aber nicht allgemein. Die Frage war allgemein und die Gründe, die ich aufgelistet habe, gelten auch für den allgemeinen Fall.
EDIT 3: Neu geordnete Punkte 1 und 4
quelle
eval
haben nichts miteinander zu tun. Eine Anwendung, die grundlegend falsch entworfen wurde, ist grundlegend falsch entworfen.eval
ist nicht mehr die Hauptursache für schlechtes Design als die Division durch Null oder der Versuch, ein Modul zu importieren, von dem bekannt ist, dass es nicht existiert.eval
ist nicht unsicher. Anwendungen sind unsicher.calc
und um Zahlen hinzuzufügen, wird es ausgeführtprint(eval("{} + {}".format(n1, n2)))
und beendet. Jetzt vertreiben Sie dieses Programm mit einem Betriebssystem. Dann erstellt jemand ein Bash-Skript, das einige Zahlen von einer Stock-Site nimmt und sie mithilfe von hinzufügtcalc
. Boom?Die Verwendung
eval
ist schwach, keine eindeutig schlechte Praxis.Es verstößt gegen das "Grundprinzip der Software". Ihre Quelle ist nicht die Summe der ausführbaren Dateien. Neben Ihrer Quelle gibt es die Argumente
eval
, die klar verstanden werden müssen. Aus diesem Grund ist es das Werkzeug der letzten Instanz.Es ist normalerweise ein Zeichen für gedankenloses Design. Es gibt selten einen guten Grund für dynamischen Quellcode, der im laufenden Betrieb erstellt wird. Mit Delegation und anderen OO-Designtechniken kann fast alles getan werden.
Dies führt zu einer relativ langsamen schnellen Kompilierung kleiner Codeteile. Ein Overhead, der durch die Verwendung besserer Entwurfsmuster vermieden werden kann.
Als Fußnote, in den Händen von gestörten Soziopathen, kann es nicht gut funktionieren. Wenn Sie jedoch mit gestörten soziopathischen Benutzern oder Administratoren konfrontiert werden, ist es am besten, ihnen nicht zuerst interpretiertes Python zu geben. In den Händen des wahrhaft Bösen kann Python eine Haftung übernehmen;
eval
erhöht das Risiko überhaupt nicht.quelle
eval
eine Art "Sicherheitslücke" ist. Als ob Python - selbst - nicht nur eine Menge interpretierter Quellen wäre, die jeder ändern könnte. Wenn man mit der "Bewertung ist eine Sicherheitslücke" konfrontiert wird, kann man nur annehmen, dass es sich um eine Sicherheitslücke in den Händen von Soziopathen handelt. Normale Programmierer ändern lediglich die vorhandene Python-Quelle und verursachen ihre Probleme direkt. Nicht indirekt durcheval
Magie.while True: pass
wäre es schwierig, mit einer Art Flucht aufzuräumen.eval()
, da es sich um eine Zeichenfolge handelt. Code von der "Außenwelt" kann nicht bereinigt werden. Saiten von außen sind nur Saiten. Mir ist unklar, wovon du sprichst. Vielleicht sollten Sie einen vollständigeren Blog-Beitrag bereitstellen und hier darauf verlinken.In diesem Fall ja. Anstatt
Sie sollten die eingebaute Funktion verwenden
setattr
:quelle
Ja, so ist es:
Hack mit Python:
Der folgende Code listet alle Aufgaben auf, die auf einem Windows-Computer ausgeführt werden.
Unter Linux:
quelle
Es ist erwähnenswert, dass es für das jeweilige Problem mehrere Alternativen zur Verwendung gibt
eval
:Das einfachste ist, wie bereits erwähnt, die Verwendung von
setattr
:Ein weniger offensichtlicher Ansatz besteht darin, das Objekt des
__dict__
Objekts direkt zu aktualisieren . Wenn Sie lediglich die Attribute initialisieren möchten, istNone
dies weniger einfach als oben beschrieben. Aber bedenken Sie Folgendes:Auf diese Weise können Sie Schlüsselwortargumente an den Konstruktor übergeben, z.
Es ermöglicht Ihnen auch, Ihre Verwendung
locals()
expliziter zu gestalten, z.... und wenn Sie wirklich
None
den Attributen zuweisen möchten, deren Namen sich befinden inlocals()
:Ein anderer Ansatz zum Bereitstellen von Standardwerten für ein Objekt für eine Liste von Attributen besteht darin, die
__getattr__
Methode der Klasse zu definieren :Diese Methode wird aufgerufen, wenn das benannte Attribut nicht auf normale Weise gefunden wird. Dieser Ansatz ist etwas unkomplizierter als das einfache Festlegen der Attribute im Konstruktor oder das Aktualisieren des
__dict__
Er hat jedoch den Vorteil, dass das Attribut nur dann erstellt wird, wenn es vorhanden ist, was die Speichernutzung der Klasse erheblich reduzieren kann.Der Sinn all dessen: Es gibt im Allgemeinen viele Gründe, die zu vermeiden sind
eval
- das Sicherheitsproblem beim Ausführen von Code, den Sie nicht kontrollieren, das praktische Problem des Codes, den Sie nicht debuggen können usw. Aber ein noch wichtigerer Grund ist, dass Sie es im Allgemeinen nicht verwenden müssen. Python stellt dem Programmierer so viele seiner internen Mechanismen zur Verfügung, dass Sie selten wirklich Code schreiben müssen, der Code schreibt.quelle
__dict__
direkt zu verwenden, geben Sie dem Objekt ein tatsächliches Wörterbuchobjekt, entweder durch Vererbung oder als Attribut.__setattr__
Überschreibungen umgangen werden , was zu unerwarteten Ergebnissen führen kann.setattr()
hat dieses Problem nicht.Andere Benutzer wiesen darauf hin, wie Ihr Code geändert werden kann, um nicht davon abhängig zu sein
eval
. Ich werde einen legitimen Anwendungsfall für die Verwendung anbieteneval
, der sogar in CPython zu finden ist: Testen .Hier ist ein Beispiel, in
test_unary.py
dem ich einen Test gefunden habe, ob(+|-|~)b'a'
einTypeError
:Die Verwendung ist hier eindeutig keine schlechte Praxis; Sie definieren die Eingabe und beobachten lediglich das Verhalten.
eval
ist praktisch zum Testen.Schauen Sie sich diese Suche an
eval
, die im CPython-Git-Repository durchgeführt wird. Tests mit eval werden häufig verwendet.quelle
Wenn
eval()
zum Verarbeiten von vom Benutzer bereitgestellten Eingaben verwendet wird, aktivieren Sie den Benutzer für Drop-to-REPL , wobei Folgendes bereitgestellt wird:Sie können damit durchkommen, aber normalerweise möchten Sie keine Vektoren für die Ausführung von beliebigem Code in Ihren Anwendungen.
quelle
Zusätzlich zur Antwort von @Nadia Alramli habe ich ein kleines Programm ausprobiert, da ich neu in Python bin und unbedingt prüfen wollte, wie sich die Verwendung
eval
auf das Timing auswirkt. Nachfolgend sind die Beobachtungen aufgeführt:quelle