19. Premier retour sur les fonctions#

Les fonctions sont un élément très important en programmation. Elles sont au coeur des bonnes pratiques et c’est pour cela que l’on vous pousse à les utiliser, à décomposer votre code.

  • Les fonctions permettent de factoriser du code, de réutiliser un morceau de code plusieurs fois, d”éviter les copier/coller. Cela ne vous parrait pas pertinent ? Vous pensez qu’un copier/coller est moins fastidieux que de devoir définir une fonction avec tous ces mots clefs, ces paramètres et ces valeurs de retour ? Vous vous trompez, car…

  • Les fonctions facilitent la maintenance du code. Vous êtes humain, vous faites des erreurs. Vous êtes même débutant en informatique, vous en commettez beaucoup. Lorsque vous devez modifier le comportement d’une fonction, vous n’avez à le faire qu’à un seul endroit. Si vous utilisez des copier/coller il est fastidieux de devoir reporter les modifications apportées aux différents endroits du code ; sans compter qu’il ne faut pas oublier d’occurence…

  • Votre code sera plus lisible avec des fonctions. En choisissant des noms pertinents pour vos fonctions, vous allez pouvoir écrire du code qui se lit « comme » un langage naturel. Cela aide à comprendre facilement ce que l’on a fait et à limiter les erreurs. C’est aussi utile lorsque plusieurs mois s’écoulent entre deux sessions de développement, cela aide à se rappeler du fonctionnement. C’est également le cas pour lire le code réaliser par quelqu’un d’autre.

  • Et surtout… les fonctions aident à déboguer votre code. En séparant le code en fonctions distinctes, il est possible de tester individuellement si une fonction se comporte comme on l’attend. Les variables d’une fonction sont locales, cela veut dire qu’on limite les effets de bord.

Maintenant que nous avons essayer de clarifier l’importance d’utiliser les fonctions, nous allons voir quelques nouveautés.

19.1. Valeurs de retour multiples#

Il est parfois nécessaire pour une fonction de renvoyer plusieurs valeurs de retour à la fois. Le mot clef return le permet. Il peut être suivi d’une série de valeurs. Dans ce cas, ces valeurs seront regroupés dans un tuple.

def f():
    return 1, 2, 3
t = f()
t
(1, 2, 3)

Python permet de stocker les multiples valeurs renvoyées par des fonctions grace à une affectation multiple.

a, b, c = f()

Cette affectation multiple peut s’utiliser de manière plus générale. On peut affecter plusieurs variables d’un coup à partir d’une séquence, pourvu qu’elle contiennent le même nombre de valeurs que de variables. Sinon on obtient une erreur : ValueError: too many values to unpack (expected 2).

a, b = (1, 2) # avec un tuple
a, b = [1, 2] # avec une liste ou même une chaîne.

19.2. Paramètres nommés et valeurs par défaut#

Pour le moment, vous avez créé des fonctions avec zero, un ou plusieurs paramètres. Python permet plus de subtilité. En particulier, pour une fonction, on distingue quatre catégorie de paramètres:

  • positionnels obligatoires ;

  • positionnels optionnels ;

  • nommés ;

  • nommés optionnels.

Les paramètres positionnels obligatoires sont ceux que l’on a rencontré jusqu’à présent. Comme leur nom l’indique, ils sont obligatoires et doivent être saisi dans un ordre bien précis. La syntaxe def f(a, b, c): permet de créer une fonction f avec trois paramètres positionnels obligatoires. À l’appel de la fonction, f(1, 2, 3), le variables a, b et c, seront initialisées avec les valeurs passées au moment de l’appel, par ordre d’apparition. Donc a=1, b=2 et c=3. Si un paramètre est manquant, une erreur sera générée au moment de l’exécution : TypeError: f() missing 1 required positional argument: 'c'.

À la suite des paramètres obligatoires, on peut ajouter des paramètres positionnels optionnels. On indique la présence de tel paramètres avec le symbole * et conventionnellement le nom de variable args. À l’appel de la fonction on pourra ajouter un nombre quelconque de paramètres positionnels à la suite des obligatoires. Ils seront stockés dans le tuple args. Voici un exemple d’utilisation.

def f(a, b, *args):
    ...
    
f(1, 2, 3, 4) # a=1, b=2, args=(3, 4)

On peut utiliser ce type d’argument pour des fonctions qui peuvent utiliser un nombre arbitraire de paramètres. Un exemple ici avec la somme.

def somme(*args):
    s = 0
    for p in args:
        s+=p
        
    return s

somme(1)
1
somme(1, 2, 3)
6

Un paramètre nommé est un paramètre avec une valeur par défaut spécifiée lors de la déclaration. On utilise le symbole = pour indiquer la valeur par défaut : param=defaut. À l’appel, il est possible d’omettre un paramètre positionnel optionnel. Voici un exemple de définition et d’appel.

L’ordre des paramètres nommés n’a pas d’importance, mais, ils doivent impérativement venir après les paramètres positionnels. Autrement, à l’excution, Python génèrera un message du type : SyntaxError: positional argument follows keyword argument.

def f(a, *args, c=1):
    print(f"a:{a}, args:{args}, c:{c}")
f(10)
a:10, args:(), c:1
f(10, 20, 30)
a:10, args:(20, 30), c:1
f(10, 20, 30, c=40)
a:10, args:(20, 30), c:40
f(10, c=40, 20)
  Cell In[12], line 1
    f(10, c=40, 20)
                  ^
SyntaxError: positional argument follows keyword argument

Enfin, les paramètres nommés optionnels sont indiqués avec ** et conventiellement le nom de variable kwargs. À l’appel, tout paramètre nommé ne correspondant pas à un paramètre avec une valeur par défaut sera ajouté au dictionnaire kwagrs.

def f(a, *args, c=1, **kwargs):
    print(f"a:{a}, args:{args}, c:{c}, kwargs:{kwargs}")
f(10)
a:10, args:(), c:1, kwargs:{}
f(10, c=30)
a:10, args:(), c:30, kwargs:{}
f(10, d=40)
a:10, args:(), c:1, kwargs:{'d': 40}
f(10, 20, 21, d=40, c=30, e=50)
a:10, args:(20, 21), c:30, kwargs:{'d': 40, 'e': 50}

Il est probable que vous n’implémentiez pas de fonction avec autre chose que les paramètres positionnels et les paramètres nommés, mais vous rencontrerez les paramètres optionnels en utilisant les bibliothèques.