{ "cells": [ { "cell_type": "markdown", "id": "50c46913", "metadata": {}, "source": [ "

Effets de bords

" ] }, { "cell_type": "markdown", "id": "4b8b1b77", "metadata": {}, "source": [ "

On appelle effet de bord la modification de valeurs référencées par des variables.\n", "

2 exemples marquants !

" ] }, { "cell_type": "markdown", "id": "5df1ddd4", "metadata": {}, "source": [ "

1) cas des variables non mutables

" ] }, { "cell_type": "code", "execution_count": null, "id": "d839ec50", "metadata": {}, "outputs": [], "source": [ "a=4\n", "b=a\n", "print(a,\"\\t\",b) # \\t permet une tabulation entre les affichages\n", "print(id(a),\"\\t\",id(b))\n", "a=2023\n", "print(a,\"\\t\",b)\n", "print(id(a),\"\\t\",id(b))" ] }, { "cell_type": "markdown", "id": "28913ef6", "metadata": {}, "source": [ "

Comme les identifiants de a et b sont identiques, ils définissent la même plage mémoire pour les valeurs de ces deux variables. Autrement dit a et b ont la même valeur.

\n", "\n", "

Cependant, toute modification de la variable a via une affectation va créer une autre plage mémoire avec un nouvel identifiant : la variable b ne sera donc pas modifiée !

" ] }, { "cell_type": "markdown", "id": "d784baa9", "metadata": {}, "source": [ "

Les variables mutables peuvent être modifiées par d'autres opérations qu'une affectation, or cela conserve l'identifiant !
Par conséquent, pour une variable de type mutable, l'identifiant ainsi que la plage mémoire allouée à la valeur de cette variable peuvent rester inchangés, même lorsque l'on change la valeur de cette variable.

" ] }, { "cell_type": "markdown", "id": "d7fe9f40", "metadata": {}, "source": [ "

2) cas des variables mutables

" ] }, { "cell_type": "code", "execution_count": null, "id": "a74201d6", "metadata": {}, "outputs": [], "source": [ "L1=[1,2,3,4]\n", "L2=L1 # on copie facilement la liste L1 en une liste L2\n", "print(L1,\"\\t\",L2)\n", "print(id(L1),\"\\t\",id(L2))\n", "L1[0]=5\n", "print(L1,\"\\t\",L2)\n", "print(id(L1),\"\\t\",id(L2))" ] }, { "cell_type": "markdown", "id": "31a8b4d1", "metadata": {}, "source": [ "

Cette manière de procéder permet un gain de temps (copie rapide) et de mémoire(une seule plage mémoire pour deux variables).
Mais elle pose un problème technique : si le contenu de la plage mémoire de la valeur de L1 est modifié, cela entraine automatiquement la modification de la valeur de L2 puisqu'ils sont référencés par le même identifiant!

\n", "\n", "Pour le programmeur Python non averti, cet effet de bord peut provoquer une erreur de programmation difficile à élucider." ] }, { "cell_type": "markdown", "id": "1159f06e", "metadata": {}, "source": [ "

Attention :

\n", "

Lors d'une affectation du type truc = machin, ce n'est pas la valeur de machin qui est recopiée, mais son identifiant!

\n", "\n" ] }, { "cell_type": "markdown", "id": "248d9eaa", "metadata": {}, "source": [ "

Comment l'éviter

\n", "

On peut copier une liste sans provoquer d'effet de bord en utilisant une deepcopy :

" ] }, { "cell_type": "code", "execution_count": null, "id": "79ef2553", "metadata": {}, "outputs": [], "source": [ "from copy import deepcopy\n", "\n", "\n", "L1 = [1, 2, 3, 4]\n", "L2 = deepcopy(L1)\n", "print(L1, \"\\t\", L2)\n", "print(id(L1),\"\\t\",id(L2))\n", "L1[0] = 5\n", "print(L1, \"\\t\", L2)\n" ] }, { "cell_type": "markdown", "id": "cb695844", "metadata": {}, "source": [ "

Cas des fonctions

" ] }, { "cell_type": "code", "execution_count": null, "id": "b9e5e494", "metadata": {}, "outputs": [], "source": [ "def f(L):\n", " L[0]=5\n", "\n", "L1=[1,2,3]\n", "L2=L1\n", "f(L1)\n", "print(L1,\"\\t\",L2)" ] }, { "cell_type": "code", "execution_count": null, "id": "440bd49a", "metadata": {}, "outputs": [], "source": [ "from copy import deepcopy\n", "def f(L):\n", " L[0]=5\n", "\n", "L1=[1,2,3]\n", "L2=deepcopy(L1)\n", "f(L1)\n", "print(L1,\"\\t\",L2)" ] }, { "cell_type": "markdown", "id": "2c892a77", "metadata": {}, "source": [ "

En résumé

On appelle effet de bord la modification de valeurs référencées par des variables.
Pour les éviter, le code intérieur d'une fonction ne doit pas modifier le code extérieur.
La copie de variables immuables (nombres, chaine de caractères) ne pose pas de souci.
Mais la copie de variables mutables (listes, dictionnaires...) provoque un effet de bord.
Il faut alors utiliser une copie \"profonde\". (deepcopy)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.7" } }, "nbformat": 4, "nbformat_minor": 5 }