Aller au contenu

Variables locales et globales

I. Les variables globales⚓︎

Définition

  • Une variable globale est une variable déclarée en dehors de toutes les fonctions.
  • Elle est accessible depuis n'importe quelle partie du code après sa déclaration.

Portée

La portée d'une variable globale est l'ensemble du module (fichier) dans lequel elle est définie. Elle peut être lue par n'importe quelle fonction dans ce module. Elle peut être modifiée par n'importe quelle fonction dans ce module si elle est mutable ou si elle est explicitement déclarée dans la fonction avec le mot-clé global.

Utilisation

Les variables globales sont souvent utilisées pour stocker des informations qui doivent être partagées entre plusieurs fonctions ou parties du programme.

II. Les variables Locales⚓︎

Définition

Une variable locale est une variable déclarée à l'intérieur d'une fonction. Elle n'est accessible qu'à l'intérieur de cette fonction.

Si on assigne une variable dans une fonction (ma_variable =) celle-ci est locale.

Attention, si on assigne une variable à l'intérieur d'une fonction, qui porte le même nom qu'une variable globale, cela peut rendre difficile la lecture et la compréhension du code.

Portée

La portée d'une variable locale est limitée à la fonction dans laquelle elle est définie. Une fois l'exécution de la fonction terminée, la variable locale est détruite.

Utilisation

Les variables locales sont utilisées pour stocker des informations temporaires qui ne sont nécessaires que dans le contexte d'une fonction particulière.

III. Inconvénients à l'utilisation d'une variable globale⚓︎

À savoir

Les variables globales peuvent être modifiées n’importe où dans le programme, ce qui rend le suivi des changements difficile. Cela peut compliquer la compréhension et la maintenance du code.

Une modification d’une variable globale dans une partie du code peut avoir des effets inattendus ailleurs.

Si on veut vraiment utiliser une variable globale, il faut lui donner le nom le plus explicite possible pour minimiser la possibilité que ce nom soit utilisé ailleurs dans le fichier et ajouter des commentaires expliquant son rôle.

IV. Exemple 1⚓︎

Exercice 1

1. Exécuter le script ci-dessous. Que se passe-t-il ?

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

Dans la fonction gagne, score est une variable locale qui n'a pas été assignée :

À la lecture du code de la fonction, l’instruction score = ... entraine la création d’une variable locale score sans valeur précisée. Ensuite à l’exécution de la fonction, pour procéder à l’affectation score = score + 10, il faut évaluer score + 10 et pour cela évaluer score qui est le nom d’une variable locale. Mais cette variable locale n’a pas de valeur.

2. Exécuter le script ci-dessous. Que se passe-t-il ?

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

score n'a pas été assignée dans la fonction affiche. Python recherche d'abord la variable dans l'espace de noms local. Si elle n'est pas trouvée localement, il cherche ensuite dans l'espace de noms global, et la trouve bien ici.

3. Exécuter le script ci-dessous. Que se passe-t-il ?

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

Ici la variable globale score a bien été modifiée car dans la fonction l’instruction global score signifie pour la fonction que la variable score utilisée n’est pas une variable locale mais est la variable globale.

4. Exécuter le script ci-dessous. Que se passe-t-il ?

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

La variable nbre est locale dans la fonction augmente. La variable globale score n'est pas modifiée.

5. Exécuter le script ci-dessous. Que se passe-t-il ?

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

Ici le paramètre de la fonction augmente est nommé score.

La variable score est locale dans la fonction augmente. La variable globale score n'est pas modifiée. Ces deux variables portent le même nom, mais ne sont pas du tout les mêmes. ⚠️ 🌵 À éviter absolument. Cela rend le code difficilement compréhensible alors que l’exécution de cette fonction produit exactement les mêmes résultats que celle vu un peu plus haut.

Python
score = 0

def augmente(nbre):
    nbre = nbre + 10

augmente(score)
print(score)

6. Nous avons vu qu'il vallait mieux éviter l'utilisation des variables globales. Modifier ci-dessous le code pour ne plus en avoir. Exactement la même situation de jeu doit être reproduite.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution
Proposition de solution
def affiche(note):
    print(note) # score est une variable globale

def gagne(note):
    return note + 10 

def perd(note):
    return note - 10

score = 0
affiche(score)
score = gagne(score)
affiche(score)
score = gagne(score)
affiche(score)
score = perd(score)
affiche(score)

V. Exemple 2⚓︎

Exercice 2

1. Exécuter le script ci-dessous. Que se passe-t-il ?

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

resultats est une variable globale qui a été modifiée en place.

2. Exécuter le script ci-dessous. Que se passe-t-il ?

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

Dans la fonction ajoute_2 , resultats est une variable locale qui n'a pas été assignée.

3. Exécuter le script ci-dessous. Que se passe-t-il ?

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

La variable resultats dans la fonction ajoute_3 est une variable locale. Une nouvelle liste a été affectée à resultats. La variable globale resultatsn'a pas été modifiée.

4. Ici le paramètre de la fonction ajoute_3 est nommé resultats.
La variable resultats est locale dans la fonction ajoute_3, or il existe une variable globale resultats. Ces deux variables portent le même nom, mais ne sont pas du tout les mêmes. Cela rend le code difficilement compréhensible.
Modifier le code ci-dessous pour éviter ce problème :

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

Exécuter le script ci-dessous. Répond-il à la question ?

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

Ce script ne répond pas à la question. resultats n'a pas été modifié.

Exécuter le script ci-dessous, et vérifier qu'il répond bien à la question.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

5. Pourquoi la fonction ajoute_4 se comporte-t-elle différemment de la fonction ajoute_3 ?

Solution
  • Dans la fonction ajoute_3 on a ma_liste = resultats donc les deux noms désignent la même liste. Mais avec ma_liste = ma_liste + [1] une nouvelle liste ma_liste a été créée.
  • Dans la fonction ajoute_4 on a ma_liste = resultats donc les deux noms désignent la même liste. L'instruction ma_liste.append(1) modifie donc en place ma_liste et resultats qui représentent la même liste. La variable globale resultats a donc été modifiée.

6. Nous avons vu qu'il vallait mieux éviter l'utilisation des variables globales. Modifier ci-dessous le code pour ne plus en avoir. Exactement la même situation doit être reproduite (ajout de 1 dans la liste à chaque fois que la fonction ajoute_5 est appelée)

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution
Proposition de solution
def ajoute_5(ma_liste):
    ma_liste.append(1)
    return ma_liste

resultats = []
resultats = ajoute_5(resultats)
print(resultats)

Crédits⚓︎

Avec l'aide judicieuse de Serge Bays et de Frédéric Zinelli.