Clarification sur l'instruction if dans le bloc try-except
Bonjour Thibault,
D'emblée, je te remercie pour ta critique sur le double emplois : le bloc try except avec à l'intérieur un if. En effet, c'est par la critique qu'on arrive à progresser - pour mon cas, toute critique est prise avec grand intérêt -. Je peux t'assurer que j'ai pris bonne note de ta critique et que je ne pense plus pouvoir m'employer à des telles incongruités, puisque c'est contraire aux usages, à la longue.
Cependant, j'avoue ne pas avoir compris, dans l'exemple que tu pris pour illustrer ton propos, la présence de data et de and dans l'instruction if data and data[0].get("message", {}).get("text"): :
Question : cette instruction n'aurait-elle pas pu s'écrire simplement if data[0].get("message", {}).get("text"): ?
Merci d'avance pour ton retour!
Bien à toi,
Franck.
Salut Franck,
Encore une fois : tu te poses les bonnes questions ;)
Avec la structure try / except, ce n'est pas grave si on fait planter le script : le except est là pour gérer l'erreur. Ce n'est pas le cas de la structure avec le if, dans laquelle on veut faire les vérifications nécessaires pour éviter que le script plante.
C'est pour cette raison que je vérifie déjà qu'on a un élément dans data avec le if data. data étant une liste, si la liste est vide, la liste sera évaluée comme False. Et en Python, avec un opérateur and, comme il faut que tous les élément soient True, si le premier élément évalué est False, Python ne continue pas avec l'évaluation des autres conditions.
Ici le if data au début te permet donc de t'assurer que tu as au moins 1 élément dans data, si c'est le cas, on continue avec l'évaluation de la condition après le and, et là j'utilise les get pour éviter de faire planter le script si la valeur associée à la clé n'est pas trouvée.
De cette façon, le if ne pourra pas planter : si la la liste data est vide, on s'arrête avant le and et on ne passe pas dans la condition. Si la liste contient un élément mais qu'ensuite on ne trouve pas la clé message ou text, on aura un objet None et donc on ne rentrera pas dans la condition.
Tu peux tester avec différents codes pour vérifier cela :
data = []
if data and data[0].get("message", {}).get("text"):
print(data[0].get("message", {}).get("text"))
else:
print("La liste est vide")
data = [{"message": {}}]
if data and data[0].get("message", {}).get("text"):
print(data[0].get("message", {}).get("text"))
else:
print("La liste est vide")
Après, ce n'est pas infaillible, par exemple un cas comme celui-ci lèvera quand même une erreur :
data = [{"message": None}]
if data and data[0].get("message", {}).get("text"):
print(data[0].get("message", {}).get("text"))
else:
print("La liste est vide")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'get'
C'est pour ça que généralement on fait des tests unitaires afin de tester plein de scénarios différents pour s'assurer que notre fonction réagit correctement pour tous les cas de figures envisagés. Et dans ce cas tu vois que le try / except est plus facile à utiliser : on sait qu'avec les manipulations qu'on s'apprête à faire on peut avoir 2 ou 3 types d'erreurs (KeyError, IndexError, AttributeError). Avec un if tu risques de te retrouver avec une ligne à rallonge difficile à lire ou à devoir découper en plusieurs conditions et vérifications ton code pour t'assurer qu'il n'y a pas d'erreurs (et là je suis parti sur un data simple, quand tu récupères des données d'API tu peux avoir des JSON beaucoup plus complexes).
Bonjour,
Si data nous vient de l'extérieur, il y a également le cas où data ...est vrai mais n'est pas une liste. C'est également pour cette raison que Python nous donne différents moyens pour vérifier éventuellement cela en fonction du contexte.
Lorsque tu te retrouves comme cela face à une instruction complexe, je recommande en général de décomposer en étapes. Rien ne nous oblige à exprimer une idée en une ligne. Si tu ne comprends pas cette expresser, c'est un signe qu'il est possible qu'un autre membre de l'équipe ne la comprenne pas.
Si tu fais l'exercice de décomposer, cela donne quelque chose comme:
# 1. Vérifier si 'data' existe et n'est pas vide et que c'est une liste
if data and isinstance(data, list):
# 2. Accéder au premier élément de 'data'
first_element = data[0]
# 3. Récupérer le dictionnaire sous la clé 'message' si elle existe,
# sinon retourner un dictionnaire vide
message = first_element.get("message", {})
# 4. Récupérer la valeur associée à la clé 'text' dans 'message'
# si elle existe, sinon None
text = message.get("text")
# 5. Vérifier si 'text' existe
if text and isinstance(text, str):
# Si toutes les conditions sont remplies, tu peux traiter 'text'
print("Texte trouvé:", text)
Cordialement, Thierry
Merci Thierry pour la démonstration parfaite par le code de la fin de mon message 😉👍
Comme tu le vois Franck, il y a plein de façons de faire les choses, le point le plus important à retenir étant de garder un code que toi et tes collègues vont comprendre et qui limite au maximum le risque d'erreur qui ne sont pas gérées.
Inscris-toi
(c'est gratuit !)
Tu dois créer un compte pour participer aux discussions.
Créer un compte