Retours de fonctions

Renvoyer une valeur avec return

Pour l’instant nos fonctions s’occupent d’afficher des valeurs mais ne renvoient rien (ou plutôt renvoient None).

def addition(a, b):
    print(a + b)

C’est-à-dire que addition(1, 2) est une expression qui s’évalue à None, malgré le texte affiché par la fonction.

>>> x = addition(1, 2)
3
>>> print(x)
None

On ne peut donc rien faire de ce résultat qui a été affiché par la fonction. Afin d’extraire le résultat, il va nous falloir le renvoyer depuis notre fonction, ce qui se fait avec le mot-clé return.

return est suivi d’une expression vers laquelle sera évalué l’appel de la fonction.

def addition(a, b):
    return a + b

On remarque que maintenant, l’appel à la fonction n’affiche plus rien (il n’y a plus de print).

>>> x = addition(1, 2)

En revanche, on récupère bien le résultat calculé dans la variable x.

>>> print(x)
3

x = addition(1, 2) est grossièrement équivalent à x = 1 + 2, l’expression addition(1, 2) valant 1 + 2.

Étant une expression à part entière, il est possible de l’utiliser comme valeur dans d’autres expressions :

>>> addition(addition(1, 1), addition(addition(1, 1), 1))
5

Plusieurs return dans une fonction

Une fonction n’est pas limitée à un seul return et il est ainsi possible d’en avoir plusieurs pour contrôler le flux d’exécution.

L’exécution de la fonction s’arrêtera au premier return rencontré, renvoyant la valeur associée à l’expression de ce return.

On pourrait par exemple imaginer une fonction division(a, b) renvoyant la division de a par b et gérant le cas de la division par zéro en renvoyant zéro.

def division(a, b):
    if b == 0:
        return 0
    return a / b

Dans les cas où b vaut zéro, on rentrera donc dans le bloc de la première condition et le return sera exécuté. On se retrouve donc à sortir de la fonction sans exécuter la suite, c’est pourquoi aucune erreur n’est ensuite levée.

>>> division(1, 2)
0.5
>>> division(2, 0)
0

Si aucun return n’est rencontré lors de l’exécution de la fonction, c’est la valeur None qui sera automatiquement renvoyée.

def secret_addition(a, b):
    if a + b == 42:
        return 42
>>> secret_addition(12, 30)
42
>>> secret_addition(12, 33)
>>> print(secret_addition(12, 33))
None

Pour rappel, la valeur None n’est par défaut pas affichée par l’interpréteur interactif, d’où l’appel à print pour la mettre en évidence.

Renvoyer plusieurs valeurs

Comme on vient de le voir, la fonction s’arrête au premier return rencontré. Une fonction renvoie donc toujours une et une seule valeur, celle de l’expression située derrière ce premier return.

Mais il existe une astuce pour faire comme si on renvoyait plusieurs valeurs en une fois : en utilisant un tuple contenant ces valeurs. C’est le cas de la fonction divmod de Python, renvoyant à la fois la division entière et le modulo.

>>> divmod(13, 4)
(3, 1)

On pourrait recoder cette fonction comme cela.

def divmod(a, b):
    return (a // b, a % b)

Les parenthèses autour des tuples étant facultatives, il est courant de les omettre pour les return, ce qui donne vraiment l’impression de renvoyer plusieurs valeurs.

def divmod(a, b):
    return a // b, a % b
Unpacking

Mais une construction très intéressante en Python à ce propos est l'unpacking, qui permet de déstructurer un tuple. Il s’agit en fait d’utiliser un « tuple de variables »1 comme membre de gauche lors d’une assignation, pour assigner les éléments du tuple de droite aux variables de gauche.

>>> (a, b) = (3, 4)
>>> a
3
>>> b
4

Encore une fois, les parenthèses sont facultatives, on a donc quelque chose qui ressemble à une affectation multiple.

>>> a, b = 3, 4

Et bien sûr, cela fonctionne avec toute expression s’évaluant comme un tuple, par exemple un appel à divmod.

>>> d, m = divmod(13, 4)
>>> d
3
>>> m
1

Parfois, certains éléments du tuple ne nous intéressent pas lors de l’unpacking, une convention dans ces cas-là est d’utiliser la variable _ pour affecter les résultats inintéressants.

def compute(x):
    return x, x*2, x*3, x*4
>>> _, a, _, b = compute(2)
>>> a
4
>>> b
8

On notera que l'unpacking est aussi possible pour des tuples d’un seul élément.

>>> values = (42,)
>>> a, = values
>>> a
42

Enfin, une propriété amusante de la construction/déconstruction de tuples est qu’elle permet facilement d’échanger les valeurs de deux variables. En effet, il suffit de construire un tuple avec les valeurs des deux variables puis de le déconstruire vers ces deux mêmes variables en les inversant.

>>> a = 3
>>> b = 5
>>> a, b = b, a
>>> a
5
>>> b
3

  1. Il ne s’agit pas à proprement parler d’un tuple (un tuple est une expression) mais d’une notation prenant la même forme.