La portée des variables
Une variable peut être "connue" dans une partie d'un programme et inconnue dans une autre partie : la "zone" dans laquelle la variable est connue est la portée (en anglais : scope) de la variable.
Dans un même programme, deux variables peuvent avoir le même nom, pourvu que leurs portées respectives n'interfèrent pas.
Un premier exemple
On affecte une variable a dans la partie principale du programme. On appelle ensuite une fonction dans laquelle une variable a est affectée.
def f() :
a = 2
print("Valeur de a dans le corps de la fonction : {} ".format(a))
print()
a = 5
print("Valeur de a dans la partie principale,")
print("avant appel de la fonction f : {}".format(a))
print()
f()
print("Valeur de a dans la partie principale,")
print("après appel de la fonction f : {}".format(a))
On obtient :
Valeur de a dans la partie principale, avant appel de la fonction f : 5 Valeur de a dans le corps de la fonction : 2 Valeur de a dans la partie principale, après appel de la fonction f : 5
La variable a de la partie principale n'est pas affectée par l'instruction a=2
de la fonction.
Lorsque Python rencontre une telle assignation à l'intérieur d'une fonction, il crée une variable locale à la fonction, qui n'interfère pas avec la variable de même nom extérieure à la fonction.
En d'autres termes, tout se passe comme si le programme était le suivant :
def f() :
b = 2
print("Valeur de b dans le corps de la fonction : {} ".format(b))
print()
a = 5
print("Valeur de a dans la partie principale,")
print("avant appel de la fonction f : {}".format(a))
print()
f()
print("Valeur de a dans la partie principale,")
print("après appel de la fonction f : {}".format(a))
Ce principe sera utilisé en permanence même sans y penser. Imaginez qu'un tel principe de portée n'existe pas : lorsqu'on écrit un gros programme, on devrait sans cesse se demander si le nom que l'on est en train d'introduire pour une simple petite routine est déjà utilisé ou non. Il est évident que l'on aurait très vite des erreurs et des variables interférant. Ou des noms de variables peu adaptés...
Un second exemple
On reprend ici l'idée du programme précédent et on cherche à modifier, dans la fonction f, la variable a de la partie principale.
def f() :
a = a+3
print("Valeur de a dans le corps de la fonction : {} ".format(a))
print()
a = 5
print("Valeur de a dans la partie principale,")
print("avant appel de la fonction f : {}".format(a))
print()
f()
print("Valeur de a dans la partie principale,")
print("après appel de la fonction f : {}".format(a))
On obtient :
File "prg.py" in f a = a+3 UnboundLocalError: local variable 'a' referenced before assignment
Il est ainsi confirmé que la variable a de la partie principale ne peut pas être modifiée dans f.
Si l'on veut malgré tout que a soit modifiée par la fonction f, le mieux est d'utiliser un paramètre et une valeur de retour.
Par exemple :
def f(x) :
x = x+3
return x
a = 5
print( 'Valeur de a : {}'.format(a) )
a = f(a)
print( 'Valeur de a : {}'.format(a) )
On obtient cette fois :
Valeur de a : 5 Valeur de a : 8
Exemple 3.
On a, malgré ce qui précède, le comportement suivant :
def f() :
print("Valeur de a dans le corps de la fonction : {} ".format(a))
print()
a = 5
print("Valeur de a dans la partie principale,")
print("avant appel de la fonction f : {}".format(a))
print()
f()
print("Valeur de a dans la partie principale,")
print("après appel de la fonction f : {}".format(a))
qui donne :
Valeur de a dans la partie principale, avant appel de la fonction f : 5 Valeur de a dans le corps de la fonction : 5 Valeur de a dans la partie principale, après appel de la fonction f : 5
Ainsi, dans le cas où l'on ne cherche pas à affecter une variable a localement à la fonction, la variable a globale semble connue (mais non disponible pour une affectation).