Quel est le principe EAFP en Python?

Réponses:

216

Extrait du glossaire :

Plus facile de demander pardon que la permission. Ce style de codage Python commun suppose l'existence de clés ou d'attributs valides et intercepte les exceptions si l'hypothèse s'avère fausse. Ce style propre et rapide se caractérise par la présence d' un grand nombre tryet exceptdéclarations. La technique contraste avec le style LBYL commun à de nombreux autres langages tels que C.

Un exemple serait une tentative d'accès à une clé de dictionnaire.

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

La version LBYL doit rechercher la clé dans le dictionnaire deux fois et peut également être considérée comme légèrement moins lisible.

Sven Marnach
la source
34
Une amélioration serait qu'un autre avantage est d'éviter les conditions de concurrence ... par exemple, essayez simplement d'ouvrir un fichier et si vous l'obtenez, vous l'avez. Au lieu de voir si vous pouvez l'obtenir , essayez de l'obtenir par la suite et réalisez que dans le laps de temps minuscule entre la vérification et la tentative d'accès, vous pouvez l'obtenir plus longtemps.
Jon Clements
23
Python fournit également un moyen d'éviter les deux, si le gestionnaire attribue simplement une valeur par défaut à xlorsque la clé n'existe pas: x = mydict.get('key')retournera Nonesi 'key'n'est pas dans my_dict; vous pouvez également le faire .get('key', <something>), et x se verra attribuer ce quelque chose si la clé n'est pas dans le dictionnaire. dict.setdefault()et collections.defaultdictsont également de bonnes choses pour éviter les excès de code.
JAB
1
Je pense except KeyErrorainsi que AttributeErrorsont simples mais certains des pires exemples. Tant de fois, j'étais coincé except AttributeErroren train de déboguer quelque chose parce que j'étais mal placé, ce qui finit par attraper une erreur d'attribut erronée plus profondément dans la chaîne. De meilleurs exemples que je pense sont: try: open() ... except: IOError. Outry: parseLine() ... except ParseError
Ski
4
@ski C'est un problème légèrement différent. Vous devez toujours garder le bloc try aussi minimal que possible pour éviter d'attraper la mauvaise exception. Notez également que je ne préfère généralement pas le style EAFP. Je réponds simplement à la question ici et j'affirme que certaines personnes la préfèrent. Je détermine au cas par cas quel code me semble le plus lisible.
Sven Marnach
1
J'ai pensé qu'il valait la peine de mentionner que Grace Hopper est probablement la source de cette phrase, avec sa citation: "Dare and Do. Il est plus facile de demander pardon que d'obtenir la permission" (pas limité à la programmation).
Fabien Snauwaert
9

Je vais essayer de l'expliquer avec un autre exemple.

Ici, nous essayons d'accéder au fichier et d'imprimer le contenu dans la console.

LBYL - Regardez avant de sauter:

Nous pourrions vouloir vérifier si nous pouvons accéder au fichier et si nous le pouvons, nous l'ouvrirons et en imprimerons le contenu. Si nous ne pouvons pas accéder au fichier, nous frapperons la elsepartie. La raison pour laquelle il s'agit d'une condition de concurrence est que nous effectuons d'abord une vérification d'accès. Au moment où nous atteignons, with open(my_file) as f:nous ne pouvons peut-être plus y accéder en raison de problèmes d'autorisation (par exemple, un autre processus obtient un verrou de fichier exclusif). Ce code générera probablement une erreur et nous ne serons pas en mesure de détecter cette erreur car nous pensions pouvoir accéder au fichier.

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 - Plus facile de demander pardon que l'autorisation:

Dans cet exemple, nous essayons simplement d'ouvrir le fichier et si nous ne pouvons pas l'ouvrir, il lancera un fichier IOError. Si nous le pouvons, nous ouvrirons le fichier et imprimerons le contenu. Donc, au lieu de demander quelque chose, nous essayons de le faire. Si cela fonctionne, tant mieux! Si ce n'est pas le cas, nous détectons l'erreur et la gérons.

# # 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
la source
Je ne suis pas sûr qu'il soit correct de décrire cela comme une condition de course. Soit le fichier est accessible, soit non.
ds4940
3
@ ds4940 C'est la condition de concurrence si l'accessibilité du fichier change entre les lignes 6 et 7, c'est-à-dire entre la vérification de l'accessibilité du fichier et son ouverture.
Markus von Broady
@MarkusvonBroady a accepté, a édité la réponse pour fournir un exemple de l'autre participant dans la condition de course.
ds4940
6

Je l'appelle «programmation optimiste». L'idée est que la plupart du temps, les gens feront ce qu'il faut et les erreurs devraient être rares. Donc, commencez par coder pour que la «bonne chose» se produise, puis détectez les erreurs si ce n'est pas le cas.

Mon sentiment est que si un utilisateur commet des erreurs, c'est lui qui devrait en subir les conséquences. Les personnes qui utilisent l'outil de la bonne manière sont accélérées.

Ingénieur
la source