Was ist das EAFP-Prinzip in Python?

Antworten:

215

Aus dem Glossar :

Es ist einfacher, um Vergebung zu bitten als um Erlaubnis. Dieser übliche Python-Codierungsstil setzt die Existenz gültiger Schlüssel oder Attribute voraus und fängt Ausnahmen ab, wenn sich die Annahme als falsch herausstellt. Dieser klare und schnelle Stil zeichnet sich durch das Vorhandensein vieler tryund exceptAussagen aus. Die Technik steht im Gegensatz zum LBYL-Stil , der vielen anderen Sprachen wie C gemeinsam ist.

Ein Beispiel wäre ein Versuch, auf einen Wörterbuchschlüssel zuzugreifen.

EAFP:

try:
    x = my_dict["key"]
except KeyError:
    # handle missing key

LBYL:

if "key" in my_dict:
    x = my_dict["key"]
else:
    # handle missing key

Die LBYL-Version muss den Schlüssel im Wörterbuch zweimal durchsuchen und wird möglicherweise auch als etwas weniger lesbar angesehen.

Sven Marnach
quelle
34
Eine Verbesserung wäre, dass ein weiterer Vorteil die Vermeidung von Rennbedingungen ist ... z. B. versuchen Sie einfach, eine Datei zu öffnen, und wenn Sie sie erhalten, haben Sie sie. Anstatt zu sehen, ob Sie es bekommen können , versuchen Sie es anschließend zu bekommen und stellen Sie fest, dass Sie es in der winzigen Zeitspanne zwischen der Prüfung und dem Zugriffsversuch länger bekommen können.
Jon Clements
23
Python bietet auch eine Möglichkeit, beide zu vermeiden, wenn der Handler nur einen Standardwert zuweist, xwenn der Schlüssel nicht vorhanden ist: x = mydict.get('key')Wird zurückgegeben, Nonewenn 'key'nicht in my_dict; Sie können dies auch tun .get('key', <something>), und dann wird x das zugewiesen, wenn der Schlüssel nicht im Wörterbuch enthalten ist. dict.setdefault()und collections.defaultdictsind nette Dinge, um auch überschüssigen Code zu vermeiden.
JAB
1
Ich denke except KeyErrorso gut wie AttributeErroreinfach, aber einige der schlimmsten Beispiele. So oft steckte ich beim Debuggen fest, weil except AttributeErrores an einer falschen Stelle platziert wurde, was dazu führte, dass falsche Attributfehler aufgefangen wurden, die tiefer in der Kette auftauchten. Bessere Beispiele, denke ich, sind : try: open() ... except: IOError. Odertry: parseLine() ... except ParseError
Ski
4
@ski Das ist ein etwas anderes Problem. Sie sollten immer den try - Block so gering wie möglich halten zu vermeiden , die falsche Ausnahme zu kontrollieren. Beachten Sie auch, dass ich den EAFP-Stil im Allgemeinen nicht bevorzuge. Ich beantworte hier nur die Frage und stelle fest, dass einige Leute sie bevorzugen. Ich entscheide von Fall zu Fall, welcher Code für mich am besten lesbar erscheint.
Sven Marnach
1
Ich dachte, es wäre erwähnenswert, dass Grace Hopper wahrscheinlich die Quelle für diesen Satz ist, mit ihrem Zitat: "Dare and Do. Es ist einfacher, um Vergebung zu bitten, als um Erlaubnis zu bitten" (nicht auf Programmierung beschränkt).
Fabien Snauwaert
9

Ich werde versuchen, es mit einem anderen Beispiel zu erklären.

Hier versuchen wir, auf die Datei zuzugreifen und den Inhalt in der Konsole zu drucken.

LBYL - Schauen Sie, bevor Sie springen:

Wir möchten möglicherweise überprüfen, ob wir auf die Datei zugreifen können, und wenn wir können, öffnen wir sie und drucken den Inhalt. Wenn wir nicht auf die Datei zugreifen können, treffen wir das elseTeil. Der Grund, warum dies eine Rennbedingung ist, ist, dass wir zuerst eine Zugangsprüfung durchführen. Bis wir es erreichen with open(my_file) as f:, können wir möglicherweise aufgrund einiger Berechtigungsprobleme nicht mehr darauf zugreifen (z. B. erhält ein anderer Prozess eine exklusive Dateisperre). Dieser Code wird wahrscheinlich einen Fehler auslösen und wir können diesen Fehler nicht abfangen, da wir dachten, wir könnten auf die Datei zugreifen.

import os

my_file = "/path/to/my/file.txt"

# Race condition
if os.access(my_file, os.R_OK):
    with open(my_file) as f:
        print(f.read())
else:
    print("File can't be accessed")

EAFP - Einfacher um Vergebung bitten als um Erlaubnis:

In diesem Beispiel versuchen wir nur, die Datei zu öffnen. Wenn wir sie nicht öffnen können, wird eine Datei ausgegeben IOError. Wenn wir können, öffnen wir die Datei und drucken den Inhalt. Anstatt etwas zu fragen , versuchen wir es zu tun. Wenn es funktioniert, großartig! Wenn dies nicht der Fall ist, erfassen wir den Fehler und behandeln ihn.

# # No race condition
try:
    f = open(my_file)
except IOError as e:
    print("File can't be accessed")
else:
    with f:
        print(f.read())
Apoorv Patne
quelle
Ich bin mir nicht sicher, ob es richtig ist, dies als Rennbedingung zu beschreiben. Entweder ist auf die Datei zugegriffen oder nicht.
ds4940
3
@ ds4940 Es ist die Race-Bedingung, wenn sich der Dateizugriff zwischen den Zeilen 6 und 7 ändert, dh zwischen der Überprüfung, ob auf die Datei zugegriffen werden kann, und dem Öffnen.
Markus von Broady
@MarkusvonBroady stimmte zu und bearbeitete die Antwort, um ein Beispiel für den anderen Teilnehmer in der Rennbedingung zu liefern.
ds4940
6

Ich nenne es "optimistische Programmierung". Die Idee ist, dass die meisten Leute das Richtige tun und es nur wenige Fehler geben sollte. Codieren Sie also zuerst, damit das "Richtige" passiert, und fangen Sie dann die Fehler ab, wenn dies nicht der Fall ist.

Ich habe das Gefühl, wenn ein Benutzer Fehler macht, sollte er derjenige sein, der unter den zeitlichen Konsequenzen leidet. Menschen, die das Werkzeug richtig einsetzen, werden durchgeschleudert.

Ingenieur
quelle