Favicon
NSI Première

Connexion

Choisir le(s) module(s) à installer :

Salut à toi, élève de NSI, comment puis-je t'aider ?

Notions avancées sur les fonctions

Portée des variables

Un exemple

Voila quelques essais d'un élève pour écrire une fonction qui modifie le score d'un joueur dans un jeu :

def augmenter_score(score): score = score + 3 score = 5 augmenter_score(score) print(score)

l'instruction print à la ligne 6 affiche la valeur de score telle qu'elle était avant l'appel de la fonction : score n'a donc pas du tout été modifiée lors de cet appel....

Tout se passe comme si il y avait en fait deux variables score différentes dans ce code, l'une dans la fonction, et l'autre en dehors...

Bon...je n'ai qu'à essayer d'affecter directement à la variable score la valeur de celle dans la fonction, en lui donnant un autre nom :

def augmenter_score(sc): sc = sc + 3 score = 5 augmenter_score(score) score = sc

Ah, maintenant j'ai une erreur...on dirait que je ne peux pas "accéder" à la variable sc depuis "l'extérieur" de la fonction....

Je sais ! Je vais directement modifier la variable score dans la fonction, sans la passer en argument :

def augmenter_score(): score = score + 3 score = 5 augmenter_score() print(score)

Non, ça ne fonctionne toujours pas...comment interpréter tout cela ??

Variables locales et globales

Selon l'endroit du code où elles ont été définies ( = initialisées ), les variables n'ont pas la même portée, c'est à dire la (ou les) partie(s) du code où elles sont effectivement accessibles( = utilisables ) :

  • Les variables définies dans une fonction sont appelées variables locales. Elles ne peuvent être utilisées que localement c’est-à-dire qu’à l’intérieur de la fonction qui les a définies.

    En fin de fonction, ces variables sont "effacées" par Python et n'existent plus en dehors de la fonction : tenter d’appeler une variable locale depuis l’extérieur de la fonction qui l’a définie provoquera donc une erreur.

    Les paramètres d'une fonction sont par définition des variables locales ( comme le paramètre score dans le premier exemple ci-dessus ).

  • Les variables définies ( = initialisées ) dans le programme principal du script, c’est-à-dire en dehors de toute fonction, sont appelées des variables globales.

On peut légitiment penser que la portée d'une variable globale est le script tout entier, fonctions y comprises; c'est le cas, mais à moitié seulement :

def multiplier_score(score): score = score*b def ajouter_score(score): b = b + 3 score = score + b score = 5 b = 3 multiplier_score(score) ajouter_score(score)
  1. l'appel de la fonction multiplier_score ( ligne 11 ) ne pose pas de problème, ce qui signifie que la fonction a pu "lire" sans problème le contenu de la variable b, variable globale.
  2. l'appel de la fonction ajouter_score ( ligne 12 ) provoque par contre une erreur, à la ligne 5, c'est à dire où on a essayé de modifier la variable globale b.

Les variables globales sont donc accessibles (= utilisables) à travers l’ensemble du script, mais en lecture seulement à l’intérieur des fonctions utilisées dans ce script.

Une fonction va pouvoir utiliser la valeur d’une variable définie globalement mais ne va pas pouvoir modifier sa valeur, c’est-à-dire la redéfinir; si on essaie de redéfinir une variable globale à l’intérieur d’une fonction, on ne fera que créer une autre variable de même nom que la variable globale qu’on souhaite redéfinir mais qui sera locale et bien distincte de cette dernière ( comme la variable score dans le premier exemple ci-dessus ).

Conséquences

Modifier une variable globale depuis une fonction

Et alors, comment résoudre notre problème : pouvoir modifier dans une fonction la valeur du score du joueur ??

Une solution serait d'utiliser le mot-clé global dans la fonction, qui lui indique que ce que l'on veut modifier est bien la variable globale score, et pas une hypothétique variable locale qui n'existe en fait pas :

def augmente_score(): global score score += 3 score = 5 augmente_score() print(score)

Et là, ça marche ! Cependant, notez bien que l'on conseille d'éviter au maximum ce genre d'usage des variables globales, c'est un véritable nid à problèmes très difficiles à résoudre...

Méthode préférable : on peut très bien s'en passer, en passant la variable globale en argument, et en récupérant la valeur modifiée de la variable comme résultat, que l'on réaffecte alors dans le programme principal à la variable globale :

def augmente_score(score): score = score + 3 # 'score' est ici bien sûr une variable LOCALE ! return score score = 5 score = augmente_score(score) print(score)

En résumé...

  • une variable définie dans une fonction est appelée variable locale.
  • une variable définie dans le programme principale est appelée variable globale.
  • la portée d'une variable locale est la fonction où elle a été définie.
  • la portée d'une variable globale est le script tout entier, mais uniquement en lecture seule au sein des fonctions.
  • si on veut ( vraiment... ) modifier une variable globale dans une fonction, on la passe comme paramètre, et on lui réaffecte le résultat renvoyé par la fonction.

Application

Vous allez essayer de réutiliser cette notion de portée de variable sur un exemple plus complexe.

Le programme ci-dessous implémente le jeu de Nim, qui se joue à deux joueurs : partant d'un tas de N allumettes ( par exemple ), chaque joueur, à tour de rôle, ne peut prendre que 1, 2 ou 3 allumettes du tas; le gagnant est celui qui prend la dernière allumettes du tas.

Vous devez corriger le code ci-dessous afin qu'il s'exécute correctement, en pensant bien aux conseils donnés ci-dessus ( pas de variable globale, nom des variables différents dans les fonctions et dans le programme principal,...)

Attention, ce code ne fonctionnera pas dans l'éditeur ci-dessous ( utilisation de la fonction input ).

Exécutez ce script sous Pyzo.

Votre but : résoudre toutes les erreurs rencontrées à l'exécution du script, et pouvoir faire une partie avec votre voisin. Trouverez-vous la stratégie gagnante ??

#################FONCTIONS################### def creer_tas(N): return "|"*N def afficher_tas(): for allumette in jeu: print(allumette, end = '') def jouer(nombre): if nombre < 4: N = N - nombre def modifier_tas(tas): tas = "|"*N ##########PROGRAMME PRINCIPAL################ N = 20 tas = creer_tas(N) while N > 0: print() afficher_tas() print() nombre = int(input("Nombre d'allumette(s) prise(s) (1, 2 ou 3 ) ? ")) jouer(nombre) modifier_tas(tas) print("Gagné !")

Lien vers les RÉPONSES