Jaka jest zasada EAFP w Pythonie?

Odpowiedzi:

215

Ze słownika :

Łatwiej prosić o przebaczenie niż o pozwolenie. Ten wspólny styl kodowania w Pythonie zakłada istnienie prawidłowych kluczy lub atrybutów i wyłapuje wyjątki, jeśli założenie okaże się fałszywe. Ten czysty i szybki styl charakteryzuje się obecnością wielu tryi exceptwypowiedzi. Technika kontrastuje ze stylem LBYL wspólnym dla wielu innych języków, takich jak C.

Przykładem może być próba uzyskania dostępu do klucza słownika.

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

Wersja LBYL musi dwukrotnie przeszukiwać klucz w słowniku i może zostać uznana za nieco mniej czytelną.

Sven Marnach
źródło
34
Ulepszeniem byłoby to, że kolejną zaletą jest unikanie warunków wyścigu ... np. Po prostu spróbuj otworzyć plik i jeśli go dostaniesz, masz go. Zamiast sprawdzać, czy możesz go zdobyć , spróbuj go później zdobyć i zdaj sobie sprawę, że w bardzo niewielkim czasie między sprawdzeniem a próbą dostępu możesz go uzyskać dłużej.
Jon Clements
23
Python zapewnia również sposób na uniknięcie obu tych sytuacji, jeśli program obsługi przypisuje tylko domyślną wartość, xgdy klucz nie istnieje: x = mydict.get('key')zwróci, Nonejeśli 'key'nie ma my_dict; możesz też zrobić .get('key', <something>), a wtedy x zostanie przypisane to coś, jeśli klucza nie ma w słowniku. dict.setdefault()i collections.defaultdictsą również fajne do unikania nadmiaru kodu.
JAB,
1
Myślę, że except KeyErrorrównie dobrze AttributeErrorsą proste, ale niektóre z najgorszych przykładów. Tak wiele razy utknąłem w debugowaniu czegoś, ponieważ except AttributeErrorzostało umieszczone w niewłaściwym miejscu, co kończyło się wyłapaniem błędu niewłaściwego atrybutu, podniesionego głębiej w łańcuchu. Lepsze przykłady myślę to: try: open() ... except: IOError. Lubtry: parseLine() ... except ParseError
Ski
4
@ski To trochę inny problem. Powinieneś zawsze utrzymywać blok try na jak najmniejszym poziomie, aby uniknąć przechwycenia niewłaściwego wyjątku. Zauważ też, że generalnie nie preferuję stylu EAFP. Odpowiadam tylko na to pytanie i stwierdzam, że niektórzy wolą to. Dla każdego przypadku określam, jaki kod wydaje mi się najbardziej czytelny.
Sven Marnach
1
Pomyślałem, że warto wspomnieć, że Grace Hopper jest prawdopodobnie źródłem tego wyrażenia, z jej cytatem: „Odważ się i zrób. Łatwiej jest prosić o wybaczenie niż o pozwolenie” (nie ogranicza się do programowania).
Fabien Snauwaert
9

Spróbuję to wyjaśnić na innym przykładzie.

Tutaj próbujemy uzyskać dostęp do pliku i wydrukować zawartość w konsoli.

LBYL - Look Before You Leap:

Możemy chcieć sprawdzić, czy możemy uzyskać dostęp do pliku, a jeśli to możliwe, otworzymy go i wydrukujemy zawartość. Jeśli nie możemy uzyskać dostępu do pliku, trafimy w tę elseczęść. Powodem, dla którego jest to stan wyścigu, jest to, że najpierw wykonujemy kontrolę dostępu. Zanim dotrzemy, with open(my_file) as f:być może nie możemy już uzyskać do niego dostępu z powodu pewnych problemów z uprawnieniami (na przykład inny proces uzyskuje wyłączną blokadę pliku). Ten kod prawdopodobnie zgłosi błąd i nie będziemy w stanie wychwycić tego błędu, ponieważ myśleliśmy, że możemy uzyskać dostęp do pliku.

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 - łatwiej prosić o przebaczenie niż o pozwolenie:

W tym przykładzie po prostu próbujemy otworzyć plik i jeśli nie możemy go otworzyć, wyrzuci plik IOError. Jeśli możemy, otworzymy plik i wydrukujemy zawartość. Więc zamiast o coś pytać , próbujemy to zrobić. Jeśli to zadziała, świetnie! Jeśli tak się nie stanie, wychwycimy błąd i zajmiemy się nim.

# # 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
źródło
Nie jestem pewien, czy można to opisać jako stan wyścigu. Plik jest dostępny lub nie.
ds4940
3
@ ds4940 Jest to stan wyścigu, jeśli dostępność pliku zmienia się między liniami 6 i 7, czyli między sprawdzeniem, czy plik jest dostępny, a jego otwarciem.
Markus von Broady
@MarkusvonBroady zgodził się, zredagował odpowiedź, aby podać przykład innego uczestnika w stanie wyścigu.
ds4940
6

Nazywam to „optymistycznym programowaniem”. Chodzi o to, że w większości przypadków ludzie postąpią właściwie, a błędów powinno być niewiele. Dlatego najpierw zakoduj, aby wydarzyło się „właściwe rozwiązanie”, a następnie wyłap błędy, jeśli tak się nie stanie.

Mam wrażenie, że jeśli użytkownik będzie popełniał błędy, to on powinien ponosić konsekwencje czasowe. Ludzie, którzy używają tego narzędzia we właściwy sposób, są przyspieszani.

Inżynier
źródło