Définition
Calculer un résultat à l'intérieur d'une fonction ne sert à rien s'il reste enfermé là où il a été produit. Pour que le reste du programme puisse l'afficher, le comparer ou le réutiliser, la fonction doit le transmettre au moment où elle se termine. C'est le rôle de return : il arrête l'exécution de la fonction et fait sortir une valeur vers l'endroit qui l'a appelée.
Voici une fonction qui calcule un prix toutes taxes comprises et le renvoie, plutôt que de se contenter de l'afficher.
def prix_ttc(prix_ht, taux=0.20):
return round(prix_ht * (1 + taux), 2)
total = prix_ttc(100) # total vaut 120.0Le résultat, une fois renvoyé, devient une valeur ordinaire qu'on peut stocker dans une variable, comparer à un montant ou transmettre à une autre fonction. C'est cette réutilisation qui distingue une fonction qui calcule d'une fonction qui se contente d'agir, comme afficher un message ou écrire dans un fichier.
Tout ce qui suit un return dans le même bloc n'est jamais exécuté. Une fonction peut en contenir plusieurs, chacun sur un chemin différent selon les conditions rencontrées, mais un seul se déclenchera à chaque appel.
Le piège de print
C'est l'erreur la plus fréquente en début d'apprentissage, et elle est rarement expliquée clairement. Beaucoup écrivent une fonction avec print à l'intérieur, puis essaient de récupérer ce qu'elle a affiché dans une variable, sans succès. Le problème n'est pas un manque d'attention : les deux instructions se ressemblent à l'écran tout en faisant des choses différentes.
print affiche du texte dans la console pendant que le programme tourne, un affichage passager destiné à l'œil de celui qui exécute le code. return transmet une valeur au programme lui-même, pour qu'il puisse continuer à s'en servir après l'appel. Voici les deux fonctions, côte à côte.
def double_affiche(n):
print(n * 2)
def double_renvoie(n):
return n * 2
a = double_affiche(5) # affiche 10, mais a vaut None
b = double_renvoie(5) # n'affiche rien, mais b vaut 10La variable a ne contient jamais le 10 qu'on a vu s'afficher, parce que double_affiche n'a rien renvoyé explicitement. Une fonction sans return renvoie implicitement None, et c'est ce qui explique les messages d'erreur du genre « unsupported operand type for NoneType » quelques lignes plus loin : la fonction a bien travaillé, elle n'a simplement rien transmis, et c'est ce rien qu'on essaie de multiplier.
Renvoyer plusieurs valeurs
Un calcul produit parfois plus d'un résultat utile, comme la longueur d'un texte et sa version en majuscules. Écrire deux fonctions séparées pour ça obligerait à refaire le même travail deux fois, ce que return évite en renvoyant plusieurs valeurs à la fois, séparées par des virgules, comme ici.
def analyser(texte):
return len(texte), texte.upper()
longueur, majuscules = analyser("bonjour")Techniquement, Python ne renvoie qu'un seul objet, un tuple, mais l'écriture reste directe des deux côtés : des virgules à l'écriture, autant de variables que de valeurs à la lecture.
return a, b et return (a, b) construisent exactement le même tuple. Les parenthèses ne changent rien à la syntaxe, elles servent seulement à rendre la lecture plus confortable quand l'expression s'allonge.
Au-delà de trois valeurs, cette forme devient difficile à relire, car seul l'ordre indique ce que contient chaque variable. Un dictionnaire ou une classe de données nomme les champs et supprime cette dépendance à la position.
Renvoyer ou modifier, il faut choisir
Une fonction qui fait les deux à la fois, rendre un résultat et modifier ce qu'on lui a donné, devient vite difficile à suivre : à la lecture de l'appel, on ne sait plus si la valeur reçue est neuve ou l'objet d'origine transformé. Les méthodes de listes de Python illustrent la convention à adopter : celles qui modifient sur place renvoient None, comme le montrent ces deux méthodes voisines.
noms = ["Zoé", "Alex", "Marie"]
trie = noms.sort() # modifie noms, trie vaut None
copie = sorted(noms) # ne touche pas à noms, copie est triéesort() trie la liste sur place et renvoie None, parce qu'elle a déjà fait le travail sur l'objet d'origine. sorted() ne touche pas à la liste de départ : elle en construit une copie triée, et c'est cette copie qu'elle renvoie.
Écrire ma_liste = ma_liste.sort() est l'un des bugs les plus fréquents chez les débutants : la liste triée disparaît, remplacée par None, et toute opération suivante échoue avec un message qui ne mentionne jamais sort().
Retenir la règle évite l'erreur : quand une fonction annonce qu'elle transforme quelque chose sur place, elle ne renvoie généralement rien d'autre.
Questions fréquentes
Une fonction peut-elle avoir plusieurs return ?
Oui, et c'est même une pratique recommandée pour écarter tôt les cas particuliers. Un return placé dès la première ligne pour un argument invalide évite d'imbriquer tout le reste du corps dans un if.
Que renvoie un return seul, sans valeur ?
Il renvoie None, exactement comme une fonction qui se termine sans return. On l'utilise pour sortir d'une fonction en cours de route quand il n'y a rien à transmettre.
Peut-on utiliser return en dehors d'une fonction ?
Non, cela déclenche une SyntaxError. Pour interrompre une boucle, l'instruction attendue est break, et pour arrêter un programme entier, c'est sys.exit(). Découper un programme en fonctions qui renvoient des valeurs plutôt qu'en blocs qui affichent est le premier réflexe qui change tout, et c'est le fil conducteur de notre formation Python.