Y a-t-il une justification pour décider lequel des try
ou des if
constructions à utiliser lors du test d'une variable pour avoir une valeur?
Par exemple, il existe une fonction qui renvoie une liste ou ne renvoie pas de valeur. Je veux vérifier le résultat avant de le traiter. Laquelle des propositions suivantes serait la plus préférable et pourquoi?
result = function();
if (result):
for r in result:
#process items
ou
result = function();
try:
for r in result:
#process items
except TypeError:
pass;
Réponses:
Vous entendez souvent que Python encourage le style EAFP ("il est plus facile de demander pardon que la permission") par rapport au style LBYL ("regardez avant de sauter"). Pour moi, c'est une question d'efficacité et de lisibilité.
Dans votre exemple (disons qu'au lieu de renvoyer une liste ou une chaîne vide, la fonction devait renvoyer une liste ou
None
), si vous vous attendez à ce que 99% du tempsresult
contienne réellement quelque chose d'itérable, j'utiliserais l'try/except
approche. Ce sera plus rapide si les exceptions sont vraiment exceptionnelles. Siresult
c'estNone
plus de 50% du temps, l'utilisationif
est probablement meilleure.Pour soutenir cela avec quelques mesures:
Ainsi, alors qu'une
if
déclaration vous coûte toujours , il est presque gratuit de mettre en place untry/except
blocage. Mais lorsqu'unException
problème survient réellement, le coût est beaucoup plus élevé.Moral:
try/except
pour le contrôle de flux,Exception
s sont réellement exceptionnels.À partir de la documentation Python:
la source
try/except
était 25% plus rapide queif key in d:
pour les cas où la clé était dans le dictionnaire. C'était beaucoup plus lent lorsque la clé n'était pas dans le dictionnaire, comme prévu, et cohérente avec cette réponse.1/1
avec timeit n'est pas un excellent choix, car elles seront optimisées (voyezdis.dis('1/1')
et notez qu'aucune division ne se produit).Votre fonction ne doit pas renvoyer de types mixtes (c.-à-d. Liste ou chaîne vide). Il doit renvoyer une liste de valeurs ou simplement une liste vide. Ensuite, vous n'avez pas besoin de tester quoi que ce soit, c'est-à-dire que votre code se réduit à:
la source
Veuillez ignorer ma solution si le code que je fournis n'est pas évident à première vue et que vous devez lire l'explication après l'exemple de code.
Puis-je supposer que "aucune valeur renvoyée" signifie que la valeur de retour est None? Si oui, ou si "aucune valeur" est False du point de vue booléen, vous pouvez effectuer les opérations suivantes, car votre code traite essentiellement "aucune valeur" comme "ne pas itérer":
Si
function()
retourne quelque chose qui n'est pas True, vous itérez sur le tuple vide, c'est-à-dire que vous n'exécutez aucune itération. C'est essentiellement LBYL.la source
Votre deuxième exemple est cassé - le code ne lèvera jamais d'exception TypeError puisque vous pouvez parcourir les chaînes et les listes. Itérer à travers une chaîne ou une liste vide est également valide - cela exécutera le corps de la boucle zéro fois.
la source
Regardez avant de sauter est préférable dans ce cas. Avec l'approche d'exception, une TypeError pourrait se produire n'importe où dans le corps de votre boucle et elle serait capturée et jetée, ce qui n'est pas ce que vous voulez et rendra le débogage délicat.
(Je suis cependant d'accord avec Brandon Corfman: renvoyer None pour "aucun élément" au lieu d'une liste vide est cassé. C'est une habitude désagréable des codeurs Java qui ne devrait pas être vue en Python. Ou Java.)
la source
En général, j'ai l'impression que les exceptions devraient être réservées aux circonstances exceptionnelles. Si l'
result
on s'attend à ce que le ne soit jamais vide (mais qu'il pourrait l'être, si, par exemple, un disque tombe en panne, etc.), la deuxième approche a du sens. Si, en revanche, un videresult
est parfaitement raisonnable dans des conditions normales, le tester avec uneif
instruction a plus de sens.J'avais en tête le scénario (le plus courant):
au lieu de l'équivalent:
la source
++
ne fonctionne pas en python, utilisez+= 1
plutôt.bobince fait remarquer à bon escient que le fait d'envelopper le deuxième cas peut également attraper TypeErrors dans la boucle, ce qui n'est pas ce que vous voulez. Si vous voulez vraiment utiliser un essai, vous pouvez tester s'il est itérable avant la boucle
Comme vous pouvez le voir, c'est plutôt moche. Je ne le suggère pas, mais il devrait être mentionné pour être complet.
la source
None
, vérifiez toujours le résultat avecis None
ouis not None
. D'un autre côté, il est également mauvais de soulever des exceptions pour des résultats légitimes. Les exceptions sont pour les choses inattendues. Exemple:str.find()
renvoie -1 si rien n'est trouvé, car la recherche elle-même s'est terminée sans erreur.En ce qui concerne les performances, l'utilisation du bloc try pour du code qui ne déclenche normalement pas d'exceptions est plus rapide que l'utilisation de l'instruction if à chaque fois. Ainsi, la décision dépend de la probabilité de cas excessifs.
la source
En règle générale, vous ne devez jamais utiliser try / catch ou tout autre élément de gestion d'exceptions pour contrôler le flux. Même si l'itération en coulisse est contrôlée via la levée d'
StopIteration
exceptions, vous devriez toujours préférer votre premier extrait de code au second.la source