{
"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
}