La leçon 11 est composée de trois parties A, B et C. Ces trois parties peuvent être complétées dans n'importe quel ordre.
Dans cette leçon, nous allons expliquer un concept appelé portée des variables (anglais «variable scope»). L'idée principale est qu'il est possible d'avoir deux variables différentes avec le même nom chaque fois qu'elles ont des portées différentes. Cela rend beaucoup plus facile à écrire et éditer des programmes, en particulier les grands programmes.
Un exemple de la portée des variables
Pour cet exemple, une partie de notre programme sera la fonction suivante:
def carré(x): valeur = x * x return valeurCeci est une fonction qui calcule le carré du nombre
x
, par exemple carré(5)
retourne 25
. Supposons maintenant que nous appelons carré
d'une autre partie du programme qui utilise aussi une variable valeur
pour un autre but:
# corps principal du programme commence ici valeur = 17 cinqcarré = carré(5) print(cinqcarré, valeur)La question est: qu'est-ce qui sera imprimé dans ce scénario? Il ya deux possibilités, si nous ne savons pas comment fonctionne Python:
- Une possibilité est que Python reconnaît que les deux valeurs des variables
valeur
doivent être "séparées" d’une façon ou d’une autre. Ainsi, l'appel àcarré
aura une valeur de retour de 25, mais la valeur devaleur
dans le corps principal restera à 17, et nous voyons la sortie25
17
. - L'autre possibilité est que lorsque
carré
est exécuté, il remplacera la valeur existante devaleur
avec 25, et nous voyons la sortie25
25
.
Voyons ce qui se passe réellement!
Nous voyons que le comportement de Python est compatible avec la possibilité #1. En fait, chaque fois vous appelez une fonction, vous ne pouvez pas affecter les variables définies en dehors de la fonction. Au lieu de cela, toutes les déclarations qui attribuent des valeurs aux variables ne concernent qu'une variable locale qui est "l'intérieur" de la fonction appelée . La raison est que Python, et la plupart des autres langues, travaillent comme ça et que cela rend beaucoup plus simple d'écrire des programmes long avec de nombreuses fonctions. En particulier, lorsque nous définissons une nouvelle fonction, nous sommes toujours autorisés à utiliser des noms de variables (y compris les variables communes comme resultat,
temp
et i
) à l'intérieur de la fonction, même si elles sont utilisées ailleurs pour des raisons différentes.
Illustration
Pour rendre cela plus explicite, ci-dessous est un tableau montrant les valeurs pendant qu’elles changent.
Après cette déclaration: | valeurs globales | valeurs locales de carré(5) |
|||
---|---|---|---|---|---|
carré |
valeur |
cinqcarré |
x |
valeur |
def carré(x): «+2 lignes de plus» | «fnc obj» | ||||
value = 17 | «fnc obj» | 17 | |||
«call carr(5)» | «fnc obj» | 17 | 5 | ||
---valeur = x * x | «fnc obj» | 17 | 5 | 25 | |
---return valeur | «fnc obj» | 17 | 25 | 5 | 25 |
print(cinqcarré, valeur) | «fnc obj» | 17 | 25 |
Dans le tableau, nous illustrons trois nouveaux détails:
- La portée locale disparaît après l'appel de fonction soit terminée.
- La façon dont nous appliquons une fonction à ses arguments est d'utiliser des variables locales! Plus précisément, lorsque nous avons appelé
carré(5)
, c'est la même chose que la création d'un nouveau champ d'application local, en ajoutant une variablex
avec la valeur5
dans le champs local, puis en exécutant le corps de la fonction dans le champs local. - (Le troisième fait n'est pas lié à la portée, mais est bon à savoir.) La définition de la fonction carré est effectivement mis en œuvre par Python de la manière suivante: un objet fonction nouvelle
«fnc obj»
est défini, puis une variablecarré
est définie comme étant égale à cet objet. En résumé, les fonctions sont un type particulier de variable.
Comme d’habitude vous pouvez voir comment le programme se comporte avec l’outil de visualisation.
x = "extérieur" def xRemplace(valeur): x = valeur xRemplace("intérieur") print(x)
x = valeur
ne concerne que la version locale de la variable x
à l'intérieur de la fonction. La version globale de x
ne change pas. (Ainsi, la fonction xRemplace
est inutile et n'a jamais d'effet.)Un autre concept similaire à la portée est un espace de noms («namespace»). Un espace de noms est comme un champ d'application pour un paquet. Donc, même si vous
importez
un paquet (comme math
) qui utilise le nom de la variable x
quelque part, il ne se chevauchent pas avec la variable x
utilisée par votre programme, car ils se situent dans différents espaces de noms.
Règles de portée : voyant vers l'extérieur
Il y a des situations où nous voulons mélanger les variables de champs locaux et globales. Un exemple courant est lorsque vous avez une variable commune initialisée une fois au début du programme, et vous voulez aussi que tout vos fonctions soient capables de lire sa valeur.
Ici, la portée locale ne contient pas une variable nommée garniturePizza
, mais ceci n’a pas causé une erreur . La règle Python pour les évaluations de variables stipule que si une variable qui doit être évaluée qui n'existe pas dans la portée locale, alors il cherche dans la portée globale. Dans notre cas, il a en effet trouvé garniturePizza
dans la portée globale. (Dans un cas plus général le corps d'une fonction appelant une autre fonction, vous aurez trois champs; Python vérifie toujours la plus locale («localmost») d'abord et va une étape à la fois vers la portée globale jusqu'à ce que la variable soit trouvée.)
Deux des exemples ci-dessus, avec commanderPizzas et xRemplace , sont presque identiques syntaxiquement. Pourquoi Python crée une nouvelle variable locale x dans xRemplace , mais aucune nouvelle garniturePizza dans commanderPizzas ? La règle de Python est la suivante: si vous lisez seulement depuis la variable, aucune nouvelle variable locale n'est créée, mais si vous écrivez dans la variable en serait-ce qu'une seule fois, alors la variable est considérée comme locale tout au long du corps de la fonction. (Ceci est la cause la plus commune de UnboundLocalError : voir ces deux questions (en anglais) [1, 2] dans la documentation officielle de Python.) |
Les arguments de fonction sont toujours traités comme de nouvelles variables locales:
Changements global
Comme beaucoup d'autres choses, le flux normal décrit ci-dessus fonctionne pour 99% des situations. Mais le reste, soit 1% du temps, vous voudrez peut-être vraiment de changer une variable globale dans une fonction. Python vous permet de faire cela en utilisant l'instruction global
. Voici une modification de xRemplace
, vu précedemment.
Comme nous l'avons mentionné plus tôt, la lecture d'une variable globale ne nécessite pas l'aide de la déclaration «global
»; seulement son écriture la nécessite.
Vous avez maintenant terminé cette leçon et vous êtes prêts à passer à la suivante.