C16.3 : Effet de bord
Les types non mutables et mutables
Variables de type non mutables
Considérons le code suivant qui met en jeu des variables de type non mutable :
a = 5
b = a
a = 8
print("a : " + str(a))
print("b : " + str(b))
Visualisons l'exécution de ce code dans pythontutor :
On observe que les variables a et b sont indépendantes. C'est toujours le cas pour des variables dont le type est non mutables.
Variables de type mutable
Considérons le code suivant qui met en jeu des variables dont le type est mutable (ici des listes, mais il en et de même pour les dictionnaires) :
l1 = [1, 2, 3]
l2 = l1
l1[1] = 10
print("l1 : " + str(l1))
print("l2 : " + str(l2))
Visualisons l'exécution de ce code dans pythontutor :
On observe que les variables l1 et l2 font référence au même objet mis en mémoire et ne sont donc pas indépendantes. C'est toujours le cas pour des variables dont le type est mutables.
Mise en évidence des effets de bords
Mise en évidence
Considérons le code suivant :
def fonc_entier(a):
a = 8
def fonc_liste(l):
l[1] = 10
print('=== avec un entier ===')
b = 15
print(b)
fonc_entier(b)
print(b)
print('=== avec une liste ===')
v = [1,2,3]
print(v)
fonc_liste(v)
print(v)
🖊️ Indiquer le contenu de l'affichage de la ligne de commande à l'issue de l'exécution de ce code.
Bilan / Définition
Considérons une fonction :
- - dont le paramètre est de type mutable ;
- - qui modifie ce paramètre lors de son exécution.
Alors, si c'est une variable qui est passée en argument lorsque la fonction est appelée, cette variable sera modifiée.
On appelle cela un effet de bord.
Lorsqu'une fonction présente des effets de bord, il faut l'indiquer dans la docstring
Programmation avec des effets de bord
Lorsqu'on souhaite qu'une fonction modifie un objet, il y a deux stratégies possibles :
- - on écrit une fonction qui renvoie un objet modifié, sans effet de bord sur le paramètre ;
- - on écrit une fonction qui ne renvoie rien, mais qui modifie par effet de bord l'objet passé en paramètre.
Exemple
Considérons les deux fonctions ci-dessous qui multiplient tous les termes d'une liste passée en paramètre par deux.
def fois2_return(liste:list)->list:
liste_r = []
for elt in liste:
liste_r.append(elt * 2)
return liste_r
def fois2_en_place(liste:list):
for i in range(len(liste)):
liste[i] = liste[i] * 2
# ==== Programme principal ====
# Utilisation de la fonction avec return
liste1 = [1,2,3,4,5]
liste1_x2 = fois2_return(liste1) # La variable liste1 n'est pas modifiée
print(liste1_x2)
# Utilisation de la fonction qui modifie en place
liste2 = [1,2,3,4,5]
fois2_en_place(liste2) # La variable liste2 est modifiée
print(liste2)
Application
Écrire deux versions (avec et sans effets de bord) d'une fonction qui prend trois paramètres (une liste et deux indices), et inverse les valeurs correspondantes.
Ainsi avec les paramètre [1, 2, 3, 4], 0, 3, il faut obtenir [4, 2, 3, 1].