Travaux pratiques
Les types mutables et non mutables en python
Vous traiterez chacun des exemples suivants en utilisant l’editeur de pythontutor
Saisir les 2 lignes de code suivantes :
Cliquer sur Visualize execution.
Dérouler alors le script ligne par ligne avec next.
créer des tests sur l’identité des variables
Revenir à la page d’edition et ajouter à la suite du script les 3 tests suivants :
Executer le programme
Chaque test ajouté est une assertion, qui arrête le programme lorsque l’un des tests retourne False
. Sinon, le programme poursuit normalement, sans rien signaler.
L’interêt est plus grand si on ajoute un commentaire explicite. C’est le message qui serait normalement affiché dans le Traceback
de la console. (trace d’erreur).
Si le programme s’arrête sur un test renvoyant False
, mais que l’on veut poursuivre les autres tests, il faudra mettre la ligne du test en commentaire:
Question a: Quelles expressions donnent True
.
Revenir dans la fenêtre d’edition et ajouter maintenant la ligne :
b = b + 1
après la ligneb = a
Question b: Refaire les tests et préciser quelles sont les expressions qui donnent True
.
types mutables
Remplacer le script précédent par celui-ci :
a = [1, 2, 3]
b = a
# a et b pointent-ils vers la même reference?
print(a is b)
# puis modifier b
b.append(4)
# afficher b puis a
print('b = {}, a = {}'.format(b,a))
Puis réaliser les mêmes opérations : Visualiser pas à pas, tester l’identité des variables avec les assertions.
Question c: Que valent a
et b
après l’execution du programme?
Question d: La copie b = a
, est-elle une copie par valeur ou par reference?
Fonctions et objets mutables/non mutables
Les objets mutables passés en argument d’une fonction sont copiés par référence. Les autres sont copiés par valeur.
Objets non mutables : copie par valeur
# définition d'une fonction carre()
def carre(x):
x = x**2
return x
# programme principal
z = 5
resultat = carre(z)
print(resultat)
Tester ce script avec l’editeur de Pythontutor.
Question e: Et resumer les étapes observées lors du déroulement du script.
Objets mutables : copie par référence
Cette fois, c’est une liste (objet mutable) qui est passée en argument :
L1 = [1,2,3]
def mafonction(L2):
L2[2]=4
print(L1 is L2)
return L2
mafonction(L1)
tester le script avec pythontutor
Question f: Et resumer les étapes observées lors du déroulement du script.
Conclusion : objets mutables et non mutables
Objets non mutables en python
Les variables simples sont non mutables. On peut réaliser des affectations, ce qui a pour effet de mettre à jour la valeur stockée dans la mémoire réservée.
Objets mutables en python
La copie d’un objet mutable se fait par référence. Cela peut entrainer des erreurs lors de la manipulation de ces objets, puisque la modification de l’un va aussi modifier toutes les variables mutables possédant la même référence.
De même, un objet mutable passé en argument d’une fonction est modifié par ce que l’on appelle : un effet de bord dans la fonction.
Imaginons un script qui prend les coordonnées de depart d’un point, coordonnees_init
, et realise une translation (ajoute 1 à x et 2 à y).
def fonction1(deplacement):
deplacement[0] = deplacement[0] + 1
deplacement[1] = deplacement[1] + 2
return deplacement
coordonnees_init = [0,0]
print(fonction1(coordonnees_init))
print(coordonnees_init)
Tester le script de la fonction1
Question g: Les nouvelles coordonnées sont stockées dans la Liste deplacement
. Comment évoluent les coordonnées dans les 2 listes? La liste de coordonnées d’origine est-elle modifiée par le script?
Ajouter maintenant le script de la fonction2
def fonction2():
deplacement = coordonnees_init
deplacement[0] = deplacement[0] + 1
deplacement[1] = deplacement[1] + 2
return deplacement
coordonnees_init = [0,0]
print(fonction2())
print(coordonnees_init)
Question h: Comment évoluent les coordonnées dans chacune des listes? deplacement
et coordonnees_init
pointent-ils vers la même reference?
Pour faire une copie de la liste a par valeur, il faudra la découper sans mentionner les 2 indices avec b = a[:]
, ou bien utiliser la fonction list
, avec b = list(a)
, ou bien utiliser la méthode copy()
:
def fonction3():
deplacement = coordonnees_init.copy()
deplacement[0] = deplacement[0] + 1
deplacement[1] = deplacement[1] + 2
return deplacement
coordonnees_init = [0,0]
print(fonction3())
print(coordonnees_init)
Question i: Cette fois, deplacement
est-il une copie par valeur ou par reference de coordonnees_init
? Précisez ce qu’est une copie par valeur.
Dictionnaires
Un dictionnaire est un tableau associatif qui stocke des couples: clé: valeur
. Un dictionnaire est entouré d’accolades {}
.
mondico = {}# un dictionnaire vide
mon_autre_dico = dict()# une autre façon de créer un dictionnaire vide
personne = {'Nom': 'Nastic', 'Prénom': 'Jim', 'Age': 42}
print(personne)
Dans l’exemple précédent, le dictionnaire personne contient trois couples clé: valeur, à savoir :
clé | valeur | |
---|---|---|
‘Nom’ | → | ‘Nastic’ |
‘Prénom’ | → | ‘Jim’ |
‘Age’ | → | 42 |
à tester:
Jim = {'Nom': 'Nastic', 'Prénom': 'Jim', 'Age': 42}
Dan = {'Nom': 'Nastic', 'Prénom': 'Dan', 'Age': 33}
famille = {}
famille['aine'] = Jim
famille['cadet'] = Dan
Puis modifier l’age de Jim:
Jim['Age'] = 43
Question j: Cela a-t-il modifié la valeur de l’age de Dan? Cela a-t-il modifié l’une des valeurs de famille
?
Conclure (famille
pointe t-il vers la reference de Jim
ou bien s’agit-il d’une copie par valeur?).
Classe et objets
Pour les objets, c’est le même principe: toute variable de classe pointe pour toute la durée du programme sur la même réference. La référence va être partagée entre toutes les instances de la classe. C’est donc le même objet !
class glace():
supplements = ['chantilly', 'praline']
g1 = glace()
g2 = glace()
print(g1.supplements,g2.supplements)
Question k1: Executer le script. Que valent g1.supplements
et g2.supplements
? Quel est leur type?
Question k2: Ajouter l’instruction g1.supplements.pop()
avant la dernière ligne. Que valent maintenant . g1.supplements
et g2.supplements
? Conclure.
Portfolio
Pour le script suivant:
a = 1
b = a
L1 = [1,2,3]
L2 = L1
L3 = list(L1)
def ma_fonction(L):
L = L + [4]
ma_fonction(L1)
Reproduire sommairement le schéma de la structure de données telle qu’elle serait représentée dans Pythontutor, à la fin de ce script.
Liens
- activité sur les copies par valeur et par reference: pythontutor
- TP5 listes, indices, méthodes
- TP6 boucles et parcours de liste