Afin de pouvoir personnaliser votre classeur sans détruire le classeur sur lequel travaille votre voisin, vous allez tout d'abord aller dans le menu File puis Make a copy.... Renommez le classeur en ajoutant votre nom à la fin du nom de fichier par exemple.

Utilisation avancée des variables

En Python, les variables sont crées automatiquement à leur première utilisation. Pour créer une variable, il suffit donc de l’utiliser en l’affectant une première fois, c’est à dire d’écrire nom_variable=valeur_de_la_variable. Une variable peut prendre n’importe quel nom, tant qu’elle respecte les règles suivantes :

  • Son nom commence de préférence par une lettre minuscule (a à z) ou majuscule (A à Z), ou bien par le caractère souligné (_)
  • Pour la suite de son nom, on peut utiliser les lettres minuscules et majuscule, le souligné et un chiffre (0 à 9)
  • Il faut éviter de préférence d’utiliser un mot réservé (commande Python)

Affectations - rappels

In [ ]:
a=7 # Affectation simple
x=y=7 # Affectation multiple
z,t="toto",8 # Affectation en parallèle
In [ ]:
print(a)
print(x,y)
print(z,t)

Variables locales - Variables globales

Variables locales

Une variable locale est une variable définie à l’intérieur d’une fonction. Elle n’est utilisable qu’à l’intérieur de celle-ci, le reste du programme ignorant totalement son existence.

Cet exemple illustre le mécanisme de variable locale et de passage de paramètre. La variable locale varLoc est utilisable à l’intérieur de la fonction maFonction et remplit son rôle.

In [ ]:
def maFonction(param):
    varLoc=4
    varLoc=varLoc+param
    print(varLoc)

maFonction(5)

Néanmoins, cette variable n'a plus d'existance à l'extérieur de la fonction. Exécutez le code suivant et trouver dans le message d'erreur ce qui prouve que la variable locale est détruite en sortant de la fonction.

In [ ]:
maFonction(3)
print(varLoc)

Variables globales

Il existe des cas ou on souhaite qu'une variable soit persistante tout au long de la vie du programme, quelque soit la fonction qui l'utilise. C'est ce qu'on appelle une variable globale.

Il faut être assez prudent dans l'utilisation de ces variables : une trop grande quantité de variables globales rend le programme difficile à lire et à maintenir. C'est une technique de programmation peu élégante.

On préfère en général avoir recours à des objets (voir le classeur sur la programmation orientée objet).

Une variable globale est définie dans le programme principal (souvent au début dans la section d’initialisa- tion). Elle est par défaut accessible en lecture seule dans l’ensemble des fonctions définies dans le programme :

In [ ]:
varGlo=5
def maFonction1():
    print ("varGlo dans fonction1",varGlo)

def maFonction2():
    varGlo=4
    print ("varGlo dans fonction2",varGlo)

print("Debut programme principal",varGlo)
maFonction1()
maFonction2()
print("Fin programme principal",varGlo)

Vous constaterez dans l'exemple ci-dessus que -varGlo est accessible en lecture dans maFonction1 -varGlo a pu être modifiée dans maFonction2 -les modifications de varGlo dans maFonction2 n'ont pas été répercutées dans le programme principal !

On peut avoir l'impression en lisant le code que varGlo prend la valeur 4 dès que maFonction2 est exécutée. En réalité, maFonction2 va créer une variable locale de même nom que varGlo qui n'aura d'existance qu'à l'intérieur de la fonction. La variable globale varGlo créée au début du programme, elle, est inchangée.

Voila pourquoi il faut être prudent quant à l'utilisation des variables globales.

Modifier une variable globale dans une fonction

Il est bien sûr possible de modifier le contenu d'une variable globale à l'intérieur d'une fonction. Pour ce faire, on utilisera la commande python global pour indiquer à la fonction les variables globales accessibles en modification.

Etudiez l'exemple suivant :

In [ ]:
varGlo=5

def maFonction3():
    global varGlo
    varGlo=4

maFonction3()
interro ("Quelle est la valeur de varGlo après appel de maFonction3 ?",varGlo)

Les références partagées : le cas des listes

Les listes Python sont des références, c’est à dire que écrire a = [(1,0,0),(0,1,0),(0,0,1)] ne signifie pas que a vaut [(1,0,0),(0,1,0),(0,0,1)] mais que a référence la liste [(1,0,0),(0,1,0),(0,0,1)], c'est à dire contient un pointeur vers la zone mémoire qui contient cette liste.

La subtilité est que la commande b = a ne va pas duppliquer le contenu de la liste mais recopier une référence sur cette même liste. Si on modifie b, alors a sera également modifié.

L’examen des deux exemples suivant illustre ce concept.

In [ ]:
a = [(1,0,0), (0,1,0), (0,0,1)]
print ("a=",a)

b = a # On copie la référence, pas la liste

b[0] = (1,1,0) # On modifie b
print("b=",b)

print("a=",a) # Ouuups !!!

Dans l'exemple ci-dessus, la modification de b entraîne sans qu'on s'y attende la modification de a !!

Ce n'est pas un bug de Python, c'est normal quand on sait comment Python gère la mémoire.

Pour s'en convaincre, on va utiliser la commande id qui permet d'obtenir l'adresse mémoire de l'objet référencé par une variable :

In [ ]:
print("adresse de a",id(a))
print("adresse de b",id(b))

Tout s'explique !! a et b son un seul et même objet !

Mais comment faire pour obtenir dans b une liste identique mais indépendante de a ?

In [ ]:
a = [(1,0,0), (0,1,0),(0,0,1)]
b = [(1,0,0), (0,1,0),(0,0,1)]
print("adresse de a",id(a))
print("adresse de b",id(b))

ah ! les adresses de a et de b sont différentes. Si je modifie b, a ne devrait pas être impacté. Vérifions le de suite !

In [ ]:
b[0] = (1,1,0) # On modifie b
print("b=",b)

print("a=",a) # Ouuuf !!!

On devra donc être prudent sur l’utilisation d’une affectation du type b=a surtout lorsqu’on travaille avec des listes ou des chaîne de caractères, des effets inattendus peuvent alors se produire.

In [ ]:
# une erreur classique
liste_desordre=[3,2,5,6,3,1]
liste_ordre=liste_desordre
liste_ordre.sort()
print ("Liste en ordre",liste_ordre)
print ("Liste de départ",liste_desordre) # oups

Et voici comment réaliser une véritable dupplication de notre liste : on utilise la méthode copy()

In [ ]:
liste_desordre=[3,2,5,6,3,1]
liste_ordre=liste_desordre.copy()
liste_ordre.sort()
print ("Liste en ordre",liste_ordre)
print ("Liste de départ",liste_desordre) # ouf

A vous de jouer

Lorsque l'on manipule des variables contenant des chaînes de caractères, manipule t-on les références vers ces chaînes ou bien les contenus des chaînes de caractères ?

Le comportement des chaînes de caractères est-il identique à celui des listes ou non ?

En vous inspirant des manipulations faites listes mais avec des chaînes de caractères, tentez d'apporter des réponses à ces questions.

In [ ]:
# Faites vos tests ici

Conclusion

Il y a deux grands types d'objets en python :

  • les objets mutables
  • les objets immuables

Les objets mutables sont des objets qui acceptent d'être modifiés sans avoir besoin d'être recopiés - on parle alors de modification sur place. Exemples : les listes, les dictionnaires, les ensembles.

Les objets immuables sont des objets qui nécessitent d'être recréés pour être modifiés. Exemple : les chaines de caractères ou les tuples.

Il faut être très prudent lors de la manipulation d'objets mutables à cause du problème des références partagées qui peut occasionner des effets de bords non désirés : modification non prévue d'autres variables que celle sur laquelle on agit.

In [ ]: