TP variables

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 modifier maintenant la ligne : b = a par b = 3.

Question b: Refaire les tests et préciser quelles sont les expressions qui donnent True.

Tester l’affectation multiple: Exprimer en une seule ligne l’affectation de 2 à a et de 3 à b:

a, b = 2, 3

Question c: Que donnent les tests d’assertion? Le résultat de l’affectation en une seule ligne est-il le même qu’en plusieurs lignes?

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 d: Que valent a et b après l’execution du programme? 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.

On pourra s’aider du cours en ligne Université Diderot

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?

Tester 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?). Reproduire le schéma de la structure de données telle que représentée dans Pythontutor.