{ "cells": [ { "cell_type": "markdown", "metadata": { "nbsphinx": "hidden" }, "source": [ "[prev: Aperçu des fonctions built-in](builtin-functions.ipynb) | [home](../index.ipynb) | [next: Gérer les exceptions](exceptions.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Noms et objets non immuables\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nous utilisons ici http://pythontutor.com pour visualiser pas à pas le déroulement d'un programme python et l'évolution des variables." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Un nom est une référence, pas une variable ...\n", "\n", "- ... la variable est l'objet référencé ; ...\n", "\n", "- ... et '`=`' ne fait donc pas de copie de variable.\n", "\n", "En Python, il est plus juste de dire que '`=`' *relie un nom à un objet*.\n", "\n", "## Malgré tout ça\n", "\n", "- on ne se gênera pas pour parler de variables\n", "- on se contentera d'être pragmatique\n", "- la surprise est de courte durée" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Deux noms peuvent désigner la même chose..." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a = [3]\n", "b = [3]\n" ] } ], "source": [ "a = [5]\n", "b = a\n", "b[0] = 3\n", "\n", "print(f\"{a = }\\n{b = }\")" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import IFrame\n", "IFrame(\"https://pythontutor.com/iframe-embed.html#code=a+%3D+%5B5%5D%0Ab+%3D+a%0Ab%5B0%5D+%3D+3&origin=opt-frontend.js&cumulative=false&heapPrimitives=true&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400\",\n", " width='100%', height=300)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[lien](http://pythontutor.com/visualize.html#code=a+%3D+%5B5%5D%0Ab+%3D+a%0Ab%5B0%5D+%3D+3&origin=opt-frontend.js&cumulative=false&heapPrimitives=true&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ... mais pas toujours" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "i = 5\n", "j = 3\n" ] } ], "source": [ "# Deux noms PEUVENT désigner la même chose\n", "# mais pas pour toujours\n", "\n", "i = 5\n", "j = i\n", "j = 3\n", "\n", "print(f\"{i = }\\n{j = }\")" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import IFrame\n", "IFrame(\"https://pythontutor.com/iframe-embed.html#code=i+%3D+5%0Aj+%3D+i%0Aj+%3D+3&origin=opt-frontend.js&cumulative=false&heapPrimitives=true&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400\",\n", " width='100%', height=300)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[lien](http://pythontutor.com/visualize.html#code=i+%3D+5%0Aj+%3D+i%0Aj+%3D+3&origin=opt-frontend.js&cumulative=false&heapPrimitives=true&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Attention aux arguments de type 'list'" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# Fonction test\n", "\n", "def somme(x) :\n", " \"Somme x avec lui-même\"\n", " x += x\n", " return x" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "avant exécution : a = 2\n", "après exécution : a = 2\n", "après exécution : b = 4\n" ] } ], "source": [ "# Test sur un entier\n", "\n", "a = 2\n", "\n", "print('avant exécution : ', f\"{a = }\")\n", "\n", "b = somme(a)\n", "\n", "print('après exécution : ', f\"{a = }\")\n", "print('après exécution : ', f\"{b = }\")" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "avant exécution : a = [1, 2]\n", "après exécution : a = [1, 2, 1, 2]\n", "après exécution : b = [1, 2, 1, 2]\n" ] } ], "source": [ "# Test sur une liste\n", "\n", "a = [1, 2]\n", "\n", "print('avant exécution : ', f\"{a = }\")\n", "\n", "b = somme(a)\n", "\n", "print('après exécution : ', f\"{a = }\")\n", "print('après exécution : ', f\"{b = }\")" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Mais que se passe-t-il?\n", "from IPython.display import IFrame\n", "IFrame(\"https://pythontutor.com/iframe-embed.html#code=def+somme(x)+%3A%0A++++%23+On+somme+x+avec+lui-m%C3%AAme%0A++++x+%2B%3D+x%0A++++return+x%0A%0A%23+entier%0Aa+%3D+2%0Ab+%3D+somme(a)%0A%0A%23+liste%0Aa+%3D+%5B1,+2%5D%0Ab+%3D+somme(a)&origin=opt-frontend.js&cumulative=false&heapPrimitives=true&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400\",\n", " width='100%', height=500)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[lien](http://pythontutor.com/visualize.html#code=def+somme(x)+%3A%0A++++%23+On+somme+x+avec+lui-m%C3%AAme%0A++++x+%2B%3D+x%0A++++return+x%0A%0A%23+entier%0Aa+%3D+2%0Ab+%3D+somme(a)%0A%0A%23+liste%0Aa+%3D+%5B1,+2%5D%0Ab+%3D+somme(a)&origin=opt-frontend.js&cumulative=false&heapPrimitives=true&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Portée des variables\n", "\n", "La résolution d'un nom suit la règle dite *LEGB* (Local > Enclosed > Global > Built-in).\n", "\n", "Assigner un nom *localement* (i.e. au sein d'une fonction) ne modifie pas le niveau global.\n", "\n", "Le mot clef **`global`** permet de modifier cette règle." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "local : X = 42\n", "global: X = 'toto'\n" ] } ], "source": [ "# pas de danger à utiliser le même nom localement et globalement\n", "\n", "X = 'toto'\n", "\n", "def f():\n", " X = 42\n", " print(f\"local : {X = }\")\n", " \n", "f()\n", "print(f\"global: {X = }\")\n", "\n" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Un cas fréquent (et potentiellement dangereux) est l'utilisation d'une variable globale dans une fonction\n", "X = 3\n", "def triple(a):\n", " return a*X\n", "\n", "triple(3)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "12" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Catastrophe : la fonction a changé de valeur retournée.\n", "X = 4\n", "triple(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**conclusion** : il faut assumer ses responsabilités quand on *modifie* un objet.\n", "\n", "**remarque** : si le nom est une référence, il n'y a pas de pointeur natif en python." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Explorer la liste `liste_de_liste` construite par :\n", "``` python\n", "x = [1, 2, 3]\n", "y = [x, x]\n", "liste_de_liste = [y, y]\n", "```\n", "Que se passe-t-il quand on modifie un élément de x ? de y ?\n", "\n", "**Plus de fun !**\n", "Construire une liste *récursive* (dont un élément est elle-même ou bien la contient)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- [Matrice de zéros](../exercises/exercises.ipynb#Exercice-9-:-matrice-de-zéros)" ] } ], "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.10.12" } }, "nbformat": 4, "nbformat_minor": 4 }