Produire une trace d'exécution
Lorsqu'on a un morceau de code, on peut souhaiter savoir dans quel ordre les instructions sont exécutées.
Principe
On veut accomplir 2 éléments principaux :
- Indiquer quelles lignes de code s'exécutent dans quel ordre.
- Indiquer les effets de chaque ligne de code.
- Indiquer la pile d'appels (si on a des fonctions).
- Exemple simple
- Avec boucle
- Avec fonction
- Valider une trace
Trace
On aura la trace suivante :
ligne exécutée | effet |
---|---|
a = 3 + 4 | a: 7 |
b = a * 2 | a: 7, b: 14 |
print(f'salut {b}') | a: 7, b: 14 affiche "salut 14" |
Dans le cas d'une séquence d'instructions, on peut voir que les instructions sont exécutées dans l'ordre de lecture du code. Simple!
Trace
On aura la trace suivante :
ligne exécutée | effet |
---|---|
i = 0 | i vaut 0 |
while i < 2: | i: 0 → condition vraie |
print(...) | i: 0 affiche "i vaut 0" |
i = i + 1 | i devient 1 |
while i < 2: | i: 1 → condition vraie |
print(...) | i: 1 affiche "i vaut 1" |
i = i + 1 | i devient 2 |
while i < 2: | i: 2 → condition fausse |
On voit que :
- On indique seulement les lignes qui s'exécutent en vrai.
- Certaines lignes s'exécutent plusieurs fois, c'est le principe de la boucle!
- On appelle ce cheminement le flot de contrôle.
Code
Si on a le code suivant :
def carre(n):
return n * n
def somme_carres(x, y):
return carre(x) + carre(y)
def affiche_resultat():
a = 2
b = 3
total = somme_carres(a, b)
print(f'La somme des carrés est : {total}')
affiche_resultat()
Trace
On indique aussi la pile d'appels, c'est-à-dire les fonctions en cours d'exécution (3e colonne).
Ce genre de code fait souvent appel à plusieurs appels de fonctions imbriqués.
On peut donc visualiser la pile d'appels comme un empilement temporaire : chaque appel s’ajoute en haut de la pile, et disparaît dès qu’il est terminé.
ligne exécutée | effet | pile d'appels |
---|---|---|
affiche_resultat() | appelle affiche_resultat() | __main__ |
a = 2 | a: 2 | affiche_resultat __main__ |
b = 3 | a: 2, b: 3 | affiche_resultat __main__ |
total = somme_carres(a, b) | a: 2, b: 3 appelle somme_carres avec 2→x, 3→y | affiche_resultat __main__ |
return carre(x) + carre(y) | x: 2, y: 3 appelle carre avec 2→n | somme_carres affiche_resultat __main__ |
return n * n | n: 2 retourne 4 | carre somme_carres affiche_resultat __main__ |
return carre(x) + carre(y) | x: 2, y: 3 appelle carre avec 3→n | somme_carres affiche_resultat __main__ |
return n * n | n: 3 retourne 9 | carre somme_carres affiche_resultat __main__ |
return carre(x) + carre(y) | retourne 13 | somme_carres affiche_resultat __main__ |
print(...) | affiche "La somme des carrés est : 13" | affiche_resultat __main__ |
Afin de valider une trace :
- Placer un point d'arrêt sur la première ligne qui s'exécute.
- Lancer l'exécution en mode débogage.
- Sauter de ligne en ligne pour voir si la trace est correcte.
Si on se rend à la fin de l'exécution et que toutes tes valeurs étaient bonnes, on a bien compris ce que fait le code.