Question

Je venais d'apprendre à moi-même Python et j'ai découvert les idiomes LBYL / EAFP en ce qui concerne la vérification des erreurs avant l'exécution du code. En Python, le style accepté semble être EAFP, et il semble bien fonctionner avec le langage.

LBYL ( L chercher B avant Y ou L eap ):

def safe_divide_1(x, y):
    if y == 0:
        print "Divide-by-0 attempt detected"
        return None
    else:
        return x/y

EAFP ( c'est E plus proche de A sk F que de P ermission ):

def safe_divide_2(x, y):
    try:
        return x/y
    except ZeroDivisionError:  
        print "Divide-by-0 attempt detected"
        return None

Ma question est la suivante: je n’avais même jamais entendu parler d’utiliser EAFP comme construction de validation de données primaire, issue d’un arrière-plan Java et C ++. EAFP est-il judicieux d’utiliser Java? Ou y a-t-il trop de frais généraux provenant d'exceptions? Je sais qu'il n'y a qu'un surcoût lorsqu'une exception est réellement générée. Je ne suis donc pas sûr de savoir pourquoi la méthode plus simple de l'EAFP n'est pas utilisée. Est-ce juste la préférence?

Était-ce utile?

La solution

Personnellement, et je pense que cela est confirmé par une convention, le PAEO n’est jamais une bonne solution. Vous pouvez y voir l'équivalent de ce qui suit:

if (o != null)
    o.doSomething();
else
    // handle

par opposition à:

try {
    o.doSomething()
}
catch (NullPointerException npe) { 
    // handle
}

De plus, tenez compte des éléments suivants:

if (a != null)
    if (b != null)
        if (c != null)
            a.getB().getC().doSomething();
        else
            // handle c null
    else
        // handle b null
else
    // handle a null

Cela peut sembler beaucoup moins élégant (et oui, c’est un exemple rudimentaire - supportez-moi), mais cela vous donne une plus grande précision dans le traitement de l’erreur, au lieu de l’emballer dans une tentative d’attraper NullPointerException , puis essayez de comprendre où et pourquoi vous l'avez obtenu.

À mon avis, le principe de la planification économique et monétaire (FEAP) ne devrait jamais être utilisé, sauf dans de rares cas. De plus, depuis que vous avez soulevé la question: oui, le bloc try-catch entraîne une surcharge , même si l'exception n'est pas levée.

Autres conseils

Si vous accédez aux fichiers, EAFP est plus fiable que LBYL, car les opérations impliquées dans LBYL ne sont pas atomiques et le système de fichiers peut changer entre le moment où vous regardez et le moment où vous sautez. En fait, le nom standard est TOCTOU - Heure de vérification, Heure d'utilisation; Les bogues causés par une vérification inexacte sont des bogues de TOCTOU.

Envisagez de créer un fichier temporaire qui doit avoir un nom unique. Le meilleur moyen de savoir si le nom de fichier choisi existe déjà est d’essayer de le créer. Assurez-vous d’utiliser des options pour vous assurer que votre opération échoue si le fichier existe déjà (en termes POSIX / Unix, l’indicateur O_EXCL sur open () ). Si vous essayez de vérifier si le fichier existe déjà (en utilisant probablement access () ), puis, entre le moment où cela indique "Non". et au moment où vous essayez de créer le fichier, quelqu'un ou quelque chose d'autre peut avoir créé le fichier.

Inversement, supposons que vous essayez de lire un fichier existant. Votre contrôle de l'existence du fichier (LBYL) peut indiquer "il est là", mais lorsque vous l'ouvrez, vous constatez qu'il n'est pas là.

Dans ces deux cas, vous devez vérifier l'opération finale - et la LBYL n'a pas automatiquement aidé.

(Si vous jouez avec les programmes SUID ou SGID, access () pose une question différente; cela peut être pertinent pour LBYL, mais le code doit toujours prendre en compte la possibilité d'un échec. )

Outre le coût relatif des exceptions en Python et en Java, n'oubliez pas qu'il existe une différence de philosophie / d'attitude entre eux. Java tente d'être très strict sur les types (et tout le reste), en exigeant des déclarations explicites et détaillées des signatures de classe / méthode. Cela suppose que vous devez savoir, à tout moment, quel type d'objet vous utilisez et ce qu'il est capable de faire. En revanche, "dactylographie" de Python signifie que vous ne savez pas avec certitude (et ne devez pas vous en soucier) quel est le type d'objet manifeste, vous devez seulement vous soucier de le faire siffler lorsque vous le lui demandez. Dans ce genre d'environnement permissif, la seule attitude saine consiste à présumer que les choses vont fonctionner, mais soyez prêt à faire face aux conséquences si elles ne le font pas. Le caractère restrictif naturel de Java ne cadre pas bien avec une approche aussi décontractée. (Cela ne vise pas à dénigrer l'approche ou la langue, mais plutôt à dire que ces attitudes font partie de l'idiome de chaque langue, et copier des idiomes entre différentes langues peut souvent conduire à une maladresse et à une mauvaise communication ...)

Les exceptions sont gérées plus efficacement en Python qu'en Java, ce qui explique au moins partiellement pourquoi vous voyez cette construction en Python. En Java, il est plus inefficace (en termes de performances) d’utiliser les exceptions de cette manière.

Considérez ces extraits de code:

def int_or_default(x, default=0):
    if x.isdigit():
        return int(x)
    else:
        return default

def int_or_default(x, default=0):
    try:
        return int(x)
    except ValueError:
        return default

Ils ont tous les deux l'air correct, non? Mais l’un d’entre eux ne l’est pas.

Le premier, en utilisant LBYL, échoue à cause d’une distinction subtile entre isdigit et isdecimal ; Lorsqu'il est appelé avec la chaîne "²³??5", il génère une erreur plutôt que de renvoyer correctement la valeur par défaut.

Ce dernier, utilisant EAFTP, donne par définition un traitement correct. Une incompatibilité comportementale n'est pas possible, car le code qui requiert l'exigence est le code qui l'exige.

Utiliser LBYL signifie prendre la logique interne et la copier dans tous les sites d'appels. Plutôt que d’avoir un encodage canonique de vos exigences, vous avez une chance gratuite de vous tromper à chaque fois que vous appelez la fonction.

Il est intéressant de noter qu'EAFTP ne traite pas des exceptions, et que le code Java, en particulier, ne doit pas utiliser les exceptions de manière généralisée. Il s’agit de donner le bon travail au bon bloc de code. Par exemple, utiliser les valeurs de retour Facultatif est une manière parfaitement valide d’écrire du code EAFTP et est bien plus efficace pour assurer l’exactitude que LBYL.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top