Compléments sur les listes

Adresses et affectations

Lorqu'une valeur est stockée sur l'ordinateur, elle se trouve à une certaine place (appelée adresse) de la mémoire de celui-ci . Par exemple,

In [23]:
hex(id(777))
Out[23]:
'0x7fa0287655f0'

Le nombre $777$ est situé à l'adresse '0x7fa028765530' de l'ordinateur. On peut visualiser la mémoire de l'ordinateur comme un immeuble, une adresse est alors le numéro d'un appartement, le contenu correspond au mobilier de celui-ci.

Lorsque l'on effectue une affectation de la forme A = valeur, on associe à A une adresse contenant valeur. Puis en saisisant print(A) on demande d'afficher le contenu de ce qui se trouve "dans" A.

In [47]:
A = 777
print(A)
777

Vérifions que l'affectation correspond en fait à une attribution d'adresse :

In [49]:
B = A
print(id(A),id(B))
140325850339888 140325850339888

On constate que A et B ont bien la même adresse.

Objets mutables et immuables

On trouve en Python différents types d'objets : les listes, les entiers etc. Certains d'entre eux peuvent être modifiés sans changer d'adresse ils sont alors dits mutables. Dans le cas contraire, ils sont immuables. On trouve dans les objets mutables : les listes, les tableaux numpy. Les chaînes de caractères, les nombres sont des objets immuables. Illustrons la différence de comportement au niveau des affectations pour ces objets :

In [51]:
A = 777
B = A
print(id(A)==id(B))
B = A +1 
print(id(A),id(B))
print(A,B)
True
140325850525744 140325850341104
777 778

Lorsque l'on a modifié la valeur de B, l'ordinateur a attribué à B une nouvelle adresse avec un contenu. En résumé, pour changer la décoration avec des objets immuables, il faut changer d'appartements... Essayons d'effectuer des opérations similaires avec des objets mutables :

In [54]:
L = [1,2,3]
M = L
print(id(L),id(M))
print(id(L)==id(M))
M[1] = 888
print(id(L),id(M))
print(L,M)
140325850521152 140325850521152
True
140325850521152 140325850521152
[1, 888, 3] [1, 888, 3]

On constate que les adresses de L et M sont inchangées et que leur contenu a été modifié. Lors de copie de d'objets mutables, il faut se demander si on veut copier le contenu dans une autre adresse ou manipuler au même endroit le contenu initial. Par analogie, avec les objets mutables on peut changer de décoration sans déménager mais attention à ne pas regretter votre ancien mobilier...

Modification en place

Un avantage des objets mutables et que l'on peut les modifer directement sans devoir consommer de la mémoire supplémentaire. Un certain nombre de fonctions sur les listes exploitent la mutabilité de ces objets. On peut citer append, del, pop par exemple.

In [58]:
L = [9,4,1,5,4,4,3]
print(id(L))
L.append(168)
print(id(L))
del(L[3])
print(L,id(L))
L.pop(2)
print(L,id(L))
140325850635072
140325850635072
[9, 4, 1, 4, 4, 3, 168] 140325850635072
[9, 4, 4, 4, 3, 168] 140325850635072

Exercices

Exercice 1

On considère le code suivant :

In [57]:
L = [1,4,6]
M = L[:]
G = [[1,2,3],[4,5,5]]
H = G[:]
  1. L et M ont-elles la même adresse ?
  2. G et H ont-elles la même adresse ?
  3. Qu'en est-il de G[0] et H[0] ? Expliquer.
  4. Modifier G[1] revient-il à modifier H[1] ?

Exercice 2

Vérifier pour les objets suivants à l'aide d'un code Pyhton s'ils sont mutables ou immuables :

  • les arrays numpy,
  • les chaînes de caractères,
  • les entiers.

Exercice 3

Écrire une fonction echange(L) prenant en argument une liste d'entiers et qui échange le premier élément de la liste avec la première occurence du minimum de la liste. À l'issue de l'appel de fonction la liste L est modifiée et la fonction ne renvoit pas de valeur.

Exercice 4

Écrire une fonction echange_ligne(tableau,i,j) qui prend en arguments une matrice, deux entiers et qui modifie tableau en échangeant les lignes d'indices i et j. À l'issue de l'appel de fonction, tableau est modifiée.