Courscours et tutoriel pythonPython

cours python d’initiation : EN SAVOIR PLUS SUR LES FONCTIONS

C’est le cours python numéro 17 de la série des cours d’initiation à python.

FONCTIONS COMME SOUS-PROGRAMMES


En informatique, un synonyme courant du terme “fonction” est “sous-programme” (en anglais : sous-programme, sous-programme). En effet, un autre avantage de l’utilisation des fonctions est de pouvoir découper un programme long et compliqué en “morceaux” distincts, qui peuvent être développés et testés séparément (voire en parallèle, confiés à des programmeurs différents). Par exemple, le programme principal d’un jeu vidéo pourrait ressembler à ceci :

initialize_graph ()
load_options ()
caractère = choisir_caractère ()
résultat = correspondance (personnage)
si résultat == Vrai :
     la victoire()
autre:
     défaite()
sortir()

Dans une maison de logiciels, un programmeur expert en graphisme pourrait s’occuper de la première fonction, tandis que des experts en intelligence artificielle pourraient développer la fonction match(), etc.

Un précepte général de l’informatique dit que les fonctions doivent être totalement indépendantes du programme principal, c’est-à-dire ne faire référence à aucune de ses ressources : la seule communication entre le programme et les fonctions doit s’effectuer via les paramètres (en entrée), et les retour (en sortie). De cette manière, il est possible de développer les fonctions séparément du programme principal : un programmeur aurait seulement besoin de savoir quelles données sa fonction entre et ce qu’elle doit retourner. Mais il y a plus : une fois que vous avez programmé une fonction qui “fait quelque chose”, vous pouvez facilement la réutiliser dans un autre programme.

VARIABLES GLOBALES ET LOCALES

Le principal problème pratique de cette approche réside dans l’utilisation des variables : si la fonction est un morceau de code séparé du programme principal, ses variables seront-elles également séparées ou seront-elles toujours les mêmes ? Si nous y réfléchissons, de nombreuses questions se posent :

  • que se passe-t-il en utilisant le même nom de variable à l’intérieur et à l’extérieur d’une fonction ?
  • si la valeur d’un paramètre est modifiée (dans la fonction), le paramètre correspondant de l’appel (dans le programme principal) changera-t-il également ?
  • si une nouvelle variable est créée à l’intérieur de la fonction, peut-on alors l’utiliser dans le programme principal ?
  • les variables définies dans le programme principal peuvent-elles être lues et écrites à l’intérieur d’une fonction ?

Les premiers langages de programmation suivaient une approche très simple : chaque nom correspondait à une et une seule variable, toujours la même, qui pouvait être librement lue et modifiée à tout moment du programme (dans le programme principal ou au sein d’une fonction). Dans de très grands programmes avec de nombreuses variables, cela a conduit à plusieurs inconvénients. Par exemple, supposons que deux programmeurs différents doivent écrire deux fonctions différentes d’un même programme : avec cette approche ils devraient “s’accorder” sur le nom des variables à utiliser, afin de ne pas courir le risque qu’une des fonctions modifie les variables de l’autre . De plus, chaque fois que vous avez besoin d’ajouter de nouvelles variables dans le programme, vous devez toujours vérifier que vous n’avez pas déjà utilisé leur nom ailleurs.

La plupart des langages modernes ont répondu à ces problèmes en créant le concept de variable globale et de variable locale :

  • Les variables créées dans le programme principal sont appelées variables globales : elles existent depuis le moment où elles sont définies jusqu’à la fin du programme, et il est toujours possible de les lire et de les écrire dans le programme principal
  • Les paramètres des fonctions et les variables créées à l’intérieur de celles-ci sont plutôt des variables locales : elles ne peuvent être lues et écrites qu’à l’intérieur de la fonction et sont détruites (c’est-à-dire supprimées de la mémoire) lorsqu’elle est quittée.

Par conséquent, les paramètres et les variables créés à l’intérieur d’une fonction sont distincts de ceux à l’extérieur, même s’ils portent le même nom : en particulier les paramètres, comme je l’ai déjà dit, sont de nouvelles variables qui contiennent une copie de la valeur utilisée dans l’appel. Voyons quelques exemples pour clarifier nos idées :

def test (x) : # x est le paramètre (variable locale)
     x = x + 1 # on change la valeur du paramètre
     print ("A l'intérieur de la fonction x =", x)
                        # écrira "Fonction interne x = 11"
                        # à la sortie de la fonction x est détruit

# démarrage du programme principal
a = 10 # on crée la variable a
print ("Avant l'appel à =", a)
                        # écrira "Avant appel à = 10"
test (a) # on passe a en paramètre à la fonction
print ("Après l'appel de =", a)
                        # écrira "Après avoir appelé a = 10": a n'a pas changé en dehors de la fonction 

Dans le premier exemple on appelle une fonction qui modifie la valeur de son paramètre : on voit qu’à la sortie de la fonction la variable utilisée dans l’appel est restée inchangée (la fonction a modifié la variable locale x mais pas la variable globale a) .

Faisons maintenant quelque chose de plus audacieux : utilisons le même nom à la fois dans le programme principal et dans la fonction. Modifier comme suit :

def test (x) : # x est le paramètre (variable locale)
     x = x + 1 # on change la valeur du paramètre
     print ("A l'intérieur de la fonction x =", x)
                        # écrira "Fonction interne x = 11"
                        # à la sortie de la fonction x est détruit

# démarrage du programme principal
x = 10 # la variable globale a le même nom que le paramètre
print ("Avant d'appeler x=", x)
                        # écrira "Avant l'appel x = 10"
test (x) # on passe x en paramètre à la fonction
print ("Après avoir appelé x =", x)
                        # écrira "Après appel à = 10": x n'a pas changé en dehors de la fonction

On voit que le résultat est exactement le même : la variable x définie dans le programme principal est globale et non le même paramètre x (local) de la fonction.

Enfin, nous créons des variables à l’intérieur de la fonction et voyons ce qui se passe :

def test (x) : # x est le paramètre (variable locale)
     x = x + 1 # on change la valeur du paramètre
     y = 20 # créons une nouvelle variable
     print ("A l'intérieur de la fonction x =", x, "et y =", y)
                        # écrira "A l'intérieur de la fonction x = 11 et y = 20"
                        # à la sortie de la fonction x et y sont détruits

# démarrage du programme principal
x = 10 # on crée la variable x
print ("Avant d'appeler x=", x)
                        # écrira "Avant l'appel x = 10"
test (x) # on passe x en paramètre à la fonction
print ("Après la fonction x=", x, "et y =", y)
                        # donnera une NameError : y est local et n'existe pas en dehors de la fonction

Voyons maintenant la réponse à la dernière question : une fonction peut-elle lire ou écrire une variable globale définie en dehors d’elle ? Le changement d’une variable globale au sein d’une fonction est considéré par les programmeurs comme une pratique à éviter, car dans le programme principal on appellera la fonction et après l’appel la variable sera mystérieusement “modifiée”, sans aucune affectation (et donc sans que le programmeur notices) Pour cela, Python a mis en place une stratégie assez compliquée, mais que vous devez connaître :

  • Règle 1 : si, à l’intérieur d’une fonction, vous voulez lire la valeur d’une variable, Python regarde d’abord dans les variables locales, et s’il ne trouve pas le nom, il regarde dans les variables globales
  • Règle 2 : Si vous souhaitez affecter une valeur à une variable, Python regarde d’abord dans les variables locales ; s’il ne trouve pas le nom, il crée une nouvelle variable locale et lui attribue la valeur

Des deux règles dérivent ces conséquences :

  • Il est possible de lire une variable globale depuis l’intérieur d’une fonction, mais uniquement si vous n’avez pas créé de variable locale du même nom : une variable locale est dite “masquer” une variable globale du même nom.
  • En revanche, il n’est pas possible de modifier une variable globale depuis l’intérieur d’une fonction : si vous essayez, seule une nouvelle variable locale portant le même nom est générée (ce qui masquera alors la variable globale correspondante si nous essayons de la lire) .

Ce mécanisme permet de créer autant de variables que l’on veut dans le corps d’une fonction, sans se soucier de leurs noms : ceux-ci n’affecteront jamais les variables définies en dehors de la fonction. Voyons un exemple :

def new_a ():
     a = 10 # ici a est local
     print ("Dans la fonction a tient", a, "et b tient", b)

a = 5 # ici a est global (différent de la fonction a)
b = 20
print ("Avant que la fonction a tienne", a, "et b tienne", b)
nouveau_a ()
print ("Après la fonction a tient", a, "et b tient", b)

La sortie du programme est celle-ci :

Avant la fonction a vaut 5 et b vaut 20
Dans la fonction a vaut 10 et b vaut 20
Après la fonction a vaut 5 et b vaut 20

La variable b est toujours restée la même (définie globalement dans le programme principal, et uniquement lue par la fonction), tandis que la variable a, définie dans la fonction, est locale et donc différente (même si elle porte le même nom) de la globale définie dans le principal du programme.

EXCEPTIONS AUX RÈGLES


La règle 2 stricte empêche complètement qu’une variable qui lui est extérieure soit modifiée depuis l’intérieur d’une fonction. Ce comportement, comme nous l’avons dit, est considéré comme dangereux, mais il est parfois impossible de l’éviter. Pensons par exemple à un jeu qui dispose de diverses options globales (résolution vidéo, volume audio, niveau de difficulté…) : celles-ci seront probablement stockées dans certaines variables globales. Si maintenant je voulais implémenter une série de fonctions edit_audio(), edit_video(), edit_difficult() pour changer ces options, il faudrait nécessairement qu’elles agissent sur ces variables globales, ce qui est impossible avec les instructions vues jusqu’ici. C’est pourquoi (généralement les langages de programmation ne suivent pas à la lettre les diktats de l’informatique théorique !) un assouplissement de la règle 2 est envisagé.

Il est possible de déclarer qu’une variable dans une fonction est globale avec l’instruction globale, suivie du nom de la variable (ou de plusieurs noms séparés par des virgules).

Editez le dernier programme comme ceci :

def new_a ():
     mondial un
     a = 10 # maintenant a est global
     print ("Dans la fonction a tient", a, "et b tient", b)

a = 5 # ici a est global
b = 20
print ("Avant que la fonction a tienne", a, "et b tienne", b)
nouveau_a ()
print ("Après la fonction a tient", a, "et b tient", b)
Copie

Et voici la sortie :

Avant la fonction a vaut 5 et b vaut 20
Dans la fonction a vaut 10 et b vaut 20
Après la fonction a vaut 10 et b vaut 20

Qu’est ce qui a changé? Dans la dernière ligne, nous avons maintenant que a est égal à 10. C’est parce que cette fois la variable a à l’intérieur de la fonction a été déclarée globale, donc la fonction agit sur la même variable que le programme principal.

NOUS CRÉONS NOTRE MODULE


Dans les leçons précédentes, nous avons souvent rencontré des situations où l’utilisateur devait entrer un nombre, par exemple, de 1 à 6, ou une réponse “s” ou “n”. Ces situations généraient une bonne quantité de code, car il fallait aussi vérifier que la saisie était correcte et éventuellement répéter la question. L’un des préceptes de base de l’informatique est la réutilisation du code : les programmeurs détestent devoir réécrire plusieurs fois le même code (plus d’efforts mais surtout plus de possibilité d’erreurs), donc une fois que vous avez écrit et vérifié un ensemble de lignes qui sûrement ” fait ce qu’il doit faire “, nous essayons généralement de le transformer en fonction afin de pouvoir le réutiliser autant de fois que nous le souhaitons.

Cette fois, nous n’écrirons pas un programme, mais un module fonction, qui contiendra diverses fonctions d’entrée (sans qu’aucun programme principal ne les appelle). Nous pouvons ensuite importer le module depuis nos programmes de la même manière que les modules Python par défaut (tant que le programme et le module sont dans le même répertoire) : from myinput import *.

Voici la première fonction :

def input_sn (invite) :
     tandis que Vrai :
         réponse = entrée (invite)
         si resp dans ["s", "n"] :
             réponse de retour
         print ("Entrée incorrecte")

Comprendre ce que fait la fonction devrait être assez simple : elle prend l’invite en paramètre (c’est-à-dire la question que nous devons poser à l’utilisateur) et renvoie la chaîne saisie par l’utilisateur, en vérifiant qu’il s’agit bien de “s” ou de “n”. Un exemple d’utilisation pourrait être le suivant (ATTENTION ! N’écrivez pas ces lignes dans le fichier, elles ne servent qu’à titre d’exemple) :

depuis mon importation d'entrée *
. . .
resp = input_sn ("Voulez-vous continuer ? (y / n)")

Une fonction un peu plus sophistiquée peut demander en second paramètre une liste de réponses possibles, en vérifiant toujours que la réponse de l’utilisateur correspond à l’une d’entre elles ; ajoutez cette autre fonction après input_sn() (comme toujours, sautez une ligne entre une fonction et une autre pour améliorer la lisibilité) :

def input_list (invite, exacte):
     tandis que Vrai :
         réponse = entrée (invite)
         si resp exactement :
             réponse de retour
         print ("Entrée incorrecte")

Comprendre ce que fait la fonction devrait être assez simple : elle prend l’invite en paramètre (c’est-à-dire la question que nous devons poser à l’utilisateur) et renvoie la chaîne saisie par l’utilisateur, en vérifiant qu’il s’agit bien de “s” ou de “n”. Un exemple d’utilisation pourrait être le suivant (ATTENTION ! N’écrivez pas ces lignes dans le fichier, elles ne servent qu’à titre d’exemple) :

from myinput import *
. . .
risp = input_sn("Voulez-vous continuer? (s/n) ")

Une fonction un peu plus sophistiquée peut demander en second paramètre une liste de réponses possibles, en vérifiant toujours que la réponse de l’utilisateur correspond à l’une d’entre elles ; ajoutez cette autre fonction après input_sn() (comme toujours, sautez une ligne entre une fonction et une autre pour améliorer la lisibilité) :

def input_lista(invite, exacte):
    while True:
        risp = input(prompt)
        if risp in esatte:
            return risp
        print("Entrée incorrecte")

Et voici un exemple de son utilisation :

from myinput import *
. . .
risp = input_lista("Voulez-vous des pâtes ou de la pizza ? ", ["pasta", "pizza"])

(notez que le deuxième paramètre doit être une liste, donc il doit être écrit entre crochets (un tuple entre crochets était également bien).

Voici une fonction qui accepte deux nombres en paramètre, en plus de l’invite, et renvoie un nombre saisi par l’utilisateur, uniquement s’il est compris entre le minimum et le maximum.

def input_int (invite, min, max):
     tandis que Vrai :
         resp = int (entrée (invite))
         si resp> = min et resp <= max :
             réponse de retour
         print ("Entrée incorrecte")

Infine una funzione più sofisticata, che richiede all’utente una scelta tra un menu di opzioni: essa prende come parametro una lista con le varie opzioni, le stampa su più righe precedute da un numero, e restituisce il numero immesso dall’utente:

def input_menu (options):
     pour i dans la plage (len (options)):
         print (i + 1, "", options [i]) # pour écrire des nombres entre 1 et len ​​(options)
     tandis que Vrai :
         resp = int (entrée ("?"))
         si resp> = 1 et resp <= len (options) :
             réponse de retour
         print ("Entrée incorrecte")

Par exemple, nous pourrions appeler la fonction comme ceci :

from myinput import *
. . .
opz = input_menu(["Nuovo", "Apri", "Salva", "Salva con nome", "Esci"])
if opz == 1:
    nuovo()
elif opz == 2:
    apri()
elif opz == 3:
    salva()
elif opz == 4:
    salva_nome()
else:
    esci()

Autres articles

QCM en programmation - Exemple PDF
La programmation est devenue une compétence incontournable dans le monde...
Read more
Exemple de QCM - Programmation en C
La programmation en C est une compétence essentielle pour les...
Read more
Introduction à la Programmation Orientée Objet (POO)
Cet article vise à : Comprendre les concepts fondamentaux de la...
Read more

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *