Aller au contenu

Programmation Python/Fonctions

Un livre de Wikilivres.

Définir une fonction

[modifier | modifier le wikicode]
Début d’un principe
Fin du principe


Une fonction Python est définie par le spécificateur "def" suivi du nom de la fonction et de ses paramètres :

def nomDeLaFonction(liste de paramètres):
    ... 
    bloc d'instructions
    ...
    return resultat
  • Vous pouvez choisir n'importe quel nom pour la fonction que vous créez, à l'exception des mots réservés du langage, et à la condition de n'utiliser aucun caractère spécial ou accentué (le caractère souligné « _ » est permis). Comme c'est le cas pour les noms de variables, il vous est conseillé d'utiliser surtout des lettres minuscules, notamment au début du nom.
  • Comme les instructions if et while, l'instruction def est une instruction composée. La ligne contenant cette instruction se termine obligatoirement par un double point, lequel introduit un bloc d'instructions que vous ne devez pas oublier d'indenter.
  • La liste de paramètres spécifie quelles informations il faudra fournir en guise d'arguments (avec leurs éventuelles valeurs par défaut) lorsque l'on voudra utiliser cette fonction (les parenthèses peuvent parfaitement rester vides si la fonction ne nécessite pas d'arguments).
  • Une fonction s'utilise pratiquement comme une instruction quelconque. Dans le corps d'un programme, un appel de fonction est constitué du nom de la fonction suivi de parenthèses.
  • Une fonction Python ne renvoie pas obligatoirement de résultat : le mot "return" est facultatif. S'il est absent, en termes de programmation on parlera alors plutôt de procédure que de fonction, et elle renverra "None".
  • Le type d'un paramètre sera le même que celui de l'argument qui aura été transmis à la fonction. Exemple :
>>> def afficher3fois(arg):
...     print arg, arg, arg

>>> afficher3fois(5)
5 5 5

>>> afficher3fois('zut')
zut zut zut

>>> afficher3fois([5, 7])
[5, 7] [5, 7] [5, 7]

>>> afficher3fois(6**2)
36 36 36

Fonctionnement

[modifier | modifier le wikicode]
def factorielle(n):
    f = 1
    i = 1
    while i <= n:
         f = f * i
         i = i + 1
    return f # la valeur retournée

factorielle(7) # 5040

Une première fonction peut appeler une deuxième fonction, qui elle-même en appelle une troisième, etc. Mais elle peut aussi s'appeler elle-même :

def factorielle(n):
    if n <= 1:
        return 1
    else:
        return n * factorielle(n-1)

factorielle(7) # 5040

Passage d'argument

[modifier | modifier le wikicode]

Une fonction accepte entre zéro et 255 d'arguments :

>>> def addition(x, y):
        return x + y

addition(3, 4) # 7

>>> def multiplication(x, y):
        return x * y

multiplication(3, 4) # 12

La signature est ici "x" et "y" en paramètre.

Ces arguments peuvent être des variables, mais aussi des fonctions, appelées alors "fonctions de rappel" ou "callbacks". Exemple :

>>> def operation(x, y, f):
        return f(x, y)

operation(3, 4, addition)         # 7
operation(3, 4, multiplication)   # 12

Arguments facultatifs

[modifier | modifier le wikicode]

Il suffit de définir une valeur par défaut à un argument pour le rendre facultatif. Naturellement, cette valeur est écrasée si l'argument est précisé :

>>> def f(x = None):
        if x:
            print(x)
print f() # None
print f(1) # 1 None

Arguments nommés

[modifier | modifier le wikicode]

Pour ne pas être obligé de remplir tous les paramètres facultatifs dans l'ordre, il est possible de n'en n'appeler que quelques-uns s'ils sont nommés :

>>> def f(p1 = 0, p2 = 0, p3):
        ...
f(p3 = 1) # 1

Fonction lambda

[modifier | modifier le wikicode]

Une fonction lambda est une fonction anonyme : elle n'est pas définie par def.

>>> def f(x):
       return x*2

>>> f(3)
6

>>> g = lambda x: x*2  # 1
>>> g(3)
6

>>> (lambda x: x*2)(3) # 2
6

1 et 2 sont des fonctions lambda.

Récupérer les arguments de la ligne de commande

[modifier | modifier le wikicode]

La variable sys.argv contient les arguments de la ligne de commande, sous forme d'une liste dont le premier élément est le nom du script invoqué. Exemple :

Si le script truc.py contient

 #!/usr/bin/python
 #-*- coding: utf-8 -*-
 import sys
 print("Arguments : ", sys.argv)

alors l'invocation :

$ python truc.py -a rien -n=nervures

produira la sortie :

Arguments :  ['truc.py', '-a', 'rien', '-n=nervures']

Si on veut récupérer l'argument n° 2 :

 #!/usr/bin/python
 #-*- coding: utf-8 -*-
 import sys
 print("Argument 2 : ", sys.argv[2])

produira la sortie :

Argument 2 : 'rien'

Déclarer les arguments

[modifier | modifier le wikicode]
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-argument_nommé', '-a', help="description", type=str, default='valeur par défaut')
parser.add_argument('arguments non nommés', nargs='*')
print parser.parse_args()

Variables locales, variables globales

[modifier | modifier le wikicode]

Lorsque nous définissons des variables à l'intérieur du corps d'une fonction, ces variables ne sont accessibles qu'à la fonction elle-même. On dit que ces variables sont des variables locales à la fonction.

En effet, chaque fois que la fonction est appelée, Python réserve pour elle (dans la mémoire de l'ordinateur) un nouvel espace de noms. Les contenus des variables locales sont stockés dans cet espace de noms qui est inaccessible depuis l'extérieur de la fonction. De plus, cet espace de noms est automatiquement détruit dès que la fonction a terminé son travail, donc si on l'appelle deux fois de suite elle recommence à zéro.

Les variables définies à l'extérieur d'une fonction sont des variables globales. Leur contenu est « visible » de l'intérieur d'une fonction, mais la fonction ne peut pas le modifier. Exemple :

>>> def mask():
...	  p = 20
...	  print p, q
...
>>> p, q = 15, 38
>>> mask()
20 38
>>> print p, q
15 38
Analysons attentivement cet exemple

Nous commençons par définir une fonction très simple (qui n'utilise d'ailleurs aucun paramètre). À l'intérieur de cette fonction, une variable p est définie, avec 20 comme valeur initiale. Cette variable p qui est définie à l'intérieur d'une fonction sera donc une variable locale.

Une fois terminée la définition de la fonction, nous revenons au niveau principal pour y définir les deux variables p et q auxquelles nous attribuons les contenus 15 et 38. Ces deux variables définies au niveau principal seront donc des variables globales.

Ainsi le même nom de variable p a été utilisé ici à deux reprises, pour définir deux variables différentes : l'une est globale et l'autre est locale. On peut constater dans la suite de l'exercice que ces deux variables sont bel et bien des variables distinctes, indépendantes, obéissant à une règle de priorité qui veut qu'à l'intérieur d'une fonction (où elles pourraient entrer en compétition), ce sont les variables définies localement qui ont la priorité.

On constate en effet que lorsque la fonction mask() est lancée, la variable globale q y est accessible, puisqu'elle est imprimée correctement. Pour p, par contre, c'est la valeur attribuée localement qui est affichée.

On pourrait croire d'abord que la fonction mask() a simplement modifié le contenu de la variable globale p (puisqu'elle est accessible). Les lignes suivantes démontrent qu'il n'en est rien : en dehors de la fonction mask(), la variable globale p conserve sa valeur initiale.

Cet état de choses peut toutefois être modifié si vous le souhaitez. Il peut se faire par exemple que vous ayez à définir une fonction qui soit capable de modifier une variable globale. Pour atteindre ce résultat, il vous suffira d'utiliser l'instruction "global". Cette instruction permet d'indiquer - à l'intérieur de la définition d'une fonction - quelles sont les variables à traiter globalement.

Autre exemple

Dans l'exemple ci-dessous, la variable à utiliser à l'intérieur de la fonction "monter()" est non seulement accessible, mais également modifiable, parce qu'elle est signalée explicitement comme étant une variable qu'il faut traiter globalement. Par comparaison, essayez le même exercice en supprimant l'instruction "global" : la variable "a" n'est plus incrémentée à chaque appel de la fonction.

>>> def monter():
...	global a
...	a = a+1
...	print a
...
>>> a = 15
>>> monter()
16
>>> monter()
17
>>>

Utilisation des fonctions dans un script

[modifier | modifier le wikicode]

Pour cette première approche des fonctions, nous n'avons utilisé jusqu'ici que le mode interactif de l'interpréteur Python.

Il est bien évident que les fonctions peuvent aussi s'utiliser dans des scripts. Veuillez donc essayer vous-même le petit programme ci-dessous, lequel calcule le volume d'une sphère à l'aide de la formule que vous connaissez certainement :

def cube(n):
   return n**3

def volumeSphere(r):
   return 4 * 3.1416 * cube(r) / 3

r = input('Entrez la valeur du rayon : ')
print 'Le volume de cette sphère vaut', volumeSphere(r)
Notes

À bien y regarder, ce programme comporte trois parties : les deux fonctions cube() et volumeSphere(), et ensuite le corps principal du programme.

Dans le corps principal du programme, il y a un appel de la fonction volumeSphere().

À l'intérieur de la fonction volumeSphere(), il y a un appel de la fonction cube().

Notez bien que les trois parties du programme ont été disposées dans un certain ordre : d'abord la définition des fonctions, et ensuite le corps principal du programme. Cette disposition est nécessaire, parce que l'interpréteur exécute les lignes d'instructions du programme l'une après l'autre, dans l'ordre où elles apparaissent dans le code source. Dans le script, la définition des fonctions doit donc précéder leur utilisation.

Pour vous en convaincre, intervertissez cet ordre (en plaçant par exemple le corps principal du programme au début), et prenez note du type de message d'erreur qui est affiché lorsque vous essayez d'exécuter le script ainsi modifié.

En fait, le corps principal d'un programme Python constitue lui-même une entité un peu particulière, qui est toujours reconnue dans le fonctionnement interne de l'interpréteur sous le nom réservé __main__ (le mot main signifie « principal », en anglais. Il est encadré par des caractères « souligné » en double, pour éviter toute confusion avec d'autres symboles). L'exécution d'un script commence toujours avec la première instruction de cette entité __main__, où qu'elle puisse se trouver dans le listing. Les instructions qui suivent sont alors exécutées l'une après l'autre, dans l'ordre, jusqu'au premier appel de fonction. Un appel de fonction est comme un détour dans le flux de l'exécution : au lieu de passer à l'instruction suivante, l'interpréteur exécute la fonction appelée, puis revient au programme appelant pour continuer le travail interrompu. Pour que ce mécanisme puisse fonctionner, il faut que l'interpréteur ait pu lire la définition de la fonction avant l'entité __main__, et celle-ci sera donc placée en général à la fin du script.

Dans notre exemple, l'entité __main__ appelle une première fonction qui elle-même en appelle une deuxième. Cette situation est très fréquente en programmation. Si vous voulez comprendre correctement ce qui se passe dans un programme, vous devez donc apprendre à lire un script, non pas de la première à la dernière ligne, mais plutôt en suivant un cheminement analogue à ce qui se passe lors de l'exécution de ce script. Cela signifie concrètement que vous devrez souvent analyser un script en commençant par ses dernières lignes !

Modules de fonctions

[modifier | modifier le wikicode]

Afin que vous puissiez mieux comprendre encore la distinction entre la définition d'une fonction et son utilisation au sein d'un programme, nous vous suggérons de placer fréquemment vos définitions de fonctions dans un module Python, et le programme qui les utilise dans un autre.

Exemple

On souhaite réaliser la série de dessins ci-dessous, à l'aide du module turtle :

Écrivez les lignes de code suivantes, et sauvegardez-les dans un fichier auquel vous donnerez le nom dessins_tortue.py :

from turtle import *
 
def carre(taille, couleur):
    "fonction qui dessine un carré de taille et de couleur déterminées"
    color(couleur)
    c =0
    while c <4:
        forward(taille)
        right(90)
        c = c +1

Vous pouvez remarquer que la définition de la fonction carre() commence par une chaîne de caractères. Cette chaîne ne joue aucun rôle fonctionnel dans le script : elle est traitée par Python comme un simple commentaire, mais qui est mémorisé à part dans un système de documentation interne automatique, lequel pourra ensuite être exploité par certains utilitaires et éditeurs « intelligents ».

Si vous programmez dans l'environnement IDLE, par exemple, vous verrez apparaître cette chaîne documentaire dans une « bulle d'aide », chaque fois que vous ferez appel aux fonctions ainsi documentées.

En fait, Python place cette chaîne dans une variable spéciale dont le nom est __doc__ (le mot « doc » entouré de deux paires de caractères « souligné »), et qui est associée à l'objet fonction comme étant l'un de ses attributs (vous en apprendrez davantage au sujet de ces attributs lorsque nous aborderons les classes d'objets).

Ainsi, vous pouvez vous-même retrouver la chaîne de documentation d'une fonction quelconque en affichant le contenu de cette variable. Exemple :

>>> def essai():
...     "Cette fonction est bien documentée mais ne fait presque rien."
...     print "rien à signaler"

>>> essai()
rien à signaler

>>> print essai.__doc__
Cette fonction est bien documentée mais ne fait presque rien.

Prenez donc la peine d'incorporer une telle chaîne explicative dans toutes vos définitions de fonctions futures : il s'agit là d'une pratique hautement recommandable.

Le fichier que vous aurez créé ainsi est dorénavant un véritable module de fonctions Python, au même titre que les modules turtle ou math que vous connaissez déjà. Vous pouvez donc l'utiliser dans n'importe quel autre script, comme celui-ci, par exemple, qui effectuera le travail demandé :

from dessins_tortue import *

up()                    # relever le crayon
goto(-150, 50)          # reculer en haut à gauche 

# dessiner dix carrés rouges, alignés :
i = 0
while i < 10:
    down()              # abaisser le crayon
    carre(25, 'red')    # tracer un carré
    up()                # relever le crayon
    forward(30)         # avancer + loin
    i = i +1

a = input()             # attendre
 

Vous pouvez à priori nommer vos modules de fonctions comme bon vous semble. Sachez cependant qu'il vous sera impossible d'importer un module si son nom est l'un des 29 mots réservés Python, car le nom du module importé deviendrait une variable dans votre script, et les mots réservés ne peuvent pas être utilisés comme noms de variables. Rappelons aussi qu'il vous faut éviter de donner à vos modules - et à tous vos scripts en général - le même nom que celui d'un module Python préexistant, sinon vous devez vous attendre à des conflits. Par exemple, si vous donnez le nom turtle.py à un exercice dans lequel vous avez placé une instruction d'importation du module "turtle", c'est l'exercice lui-même que vous allez importer !

Exercices

  1. 1.2.Définissez une fonction ligneCar(n, ca) qui renvoie une chaîne de n caractères ca.
  2. Définissez une fonction surfCercle(R). Cette fonction doit renvoyer la surface (l'aire) d'un cercle dont on lui a fourni le rayon R en argument. Par exemple, l'exécution de l'instruction :
    print surfCercle(2.5) doit donner le résultat 19.635
  3. Définissez une fonction volBoite(x1,x2,x3) qui renvoie le volume d'une boîte parallélépipédique dont on fournit les trois dimensions x1, x2, x3 en arguments. Par exemple, l'exécution de l'instruction :
    print volBoite(5.2, 7.7, 3.3) doit donner le résultat : 132.13
  4. Définissez une fonction maximum(n1,n2,n3) qui renvoie le plus grand de 3 nombres n1, n2, n3 fournis en arguments. Par exemple, l'exécution de l'instruction :
    print maximum(2,5,4) doit donner le résultat : 5
  5. Complétez le module de fonctions graphiques dessins_tortue.py.
    Commencez par ajouter un paramètre angle à la fonction carre(), de manière à ce que les carrés puissent être tracés dans différentes orientations. Définissez ensuite une fonction triangle(taille, couleur, angle) capable de dessiner un triangle équilatéral d'une taille, d'une couleur et d'une orientation bien déterminées.
    Testez votre module à l'aide d'un programme qui fera appel à ces fonctions à plusieurs reprises, avec des arguments variés pour dessiner une série de carrés et de triangles :
  6. Ajoutez au module de l'exercice précédent une fonction etoile5() spécialisée dans le dessin d'étoiles à 5 branches. Dans votre programme principal, insérez une boucle qui dessine une rangée horizontale de 9 petites étoiles de tailles variées :
  7. Ajoutez au module de l'exercice précédent une fonction etoile6() capable de dessiner une étoile à 6 branches, elle-même constituée de deux triangles équilatéraux imbriqués. Cette nouvelle fonction devra faire appel à la fonction triangle() définie précédemment.
    Votre programme principal dessinera également une série de ces étoiles :
  8. Définissez une fonction compteCar(ca,ch) qui renvoie le nombre de fois que l'on rencontre le caractère ca dans la chaîne de caractères ch. Par exemple, l'exécution de l'instruction : print compteCar('e','Cette phrase est un exemple') doit donner le résultat : 7
  9. Définissez une fonction indexMax(liste) qui renvoie l'index de l'élément ayant la valeur la plus élevée dans la liste transmise en argument. Exemple d'utilisation :
    serie = [5, 8, 2, 1, 9, 3, 6, 7]
    print indexMax(serie)
    4
  10. Définissez une fonction nomMois(n) qui renvoie le nom du ne mois de l'année.
    Par exemple, l'exécution de l'instruction :
    print nomMois(4) doit donner le résultat : Avril
  11. Définissez une fonction inverse(ch) qui permette d'inverser les l'ordre des caractères d'une chaîne quelconque. (La chaîne inversée sera renvoyée au programme appelant).
  12. Définissez une fonction compteMots(ph) qui renvoie le nombre de mots contenus dans la phrase ph (On considère comme mots les ensembles de caractères inclus entre des espaces).

Solution

  1. Réfléchissez !
  2. from math import pi
    
    def surfCercle(r):
        "Surface d'un cercle de rayon r"
        return pi * r**2
    
    # test :
    print surfCercle(2.5)
    
  3. def volBoite(x1, x2, x3):
        "Volume d'une boîte parallélipipédique"
        return x1 * x2 * x3
    
    # test :
    print volBoite(5.2, 7.7, 3.3)
    
  4. def maximum(n1, n2, n3):
        "Renvoie le plus grand de trois nombres"
        if n1 >= n2 and n1 >= n3:
            return n1
        elif n2 >= n1 and n2 >= n3:
            return n2
        else:
            return n3
    
    # test :
    print maximum(4.5, 5.7, 3.9)
    
  5. Réfléchissez !
  6. Réfléchissez !
  7. Réfléchissez !
  8. def compteCar(ca, ch):
        "Renvoie le nombre de caractères ca trouvés dans la chaîne ch"
        i, tot = 0, 0
        while i < len(ch):
            if ch[i] == ca:
                tot = tot + 1
            i = i + 1
        return tot    
            
    # test :
    print compteCar("e","Cette chaîne est un exemple")
    
  9. def indexMax(tt):
        "renvoie l'indice du plus grand élément de la liste tt"
        i, max = 0, 0
        while i < len(tt):
            if tt[i] > max :
                max, imax = tt[i], i
            i = i + 1    
        return imax
    
    # test :
    serie = [5, 8, 2, 1, 9, 3, 6, 4]
    print indexMax(serie)
    
  10. def nomMois(n):
        "renvoie le nom du n-ième mois de l'année"
        mois = ['Janvier,', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet',
                'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
        return mois[n -1]       # les indices sont numérotés à partir de zéro
    
    # test :
    print nomMois(4)
    
  11. Réfléchissez !
  12. Réfléchissez !


Exercices

  1. Modifiez la fonction volBoite(x1,x2,x3) que vous avez définie dans un exercice précédent, de manière à ce qu'elle puisse être appelée avec trois, deux, un seul, ou même aucun argument. Utilisez pour ceux ci des valeurs par défaut égales à) 10.
    Par exemple :
    print volBoite() doit donner le résultat : 1000
    print volBoite(5.2) doit donner le résultat : 520.0
    print volBoite(5.2, 3) doit donner le résultat : 156.0
  2. Modifiez la fonction volBoite(x1,x2,x3) ci-dessus de manière à ce qu'elle puisse être appelée avec un, deux, ou trois arguments. Si un seul est utilisé, la boîte est considérée comme cubique (l'argument étant l'arête de ce cube). Si deux sont utilisés, la boîte est considérée comme un prisme à base carrée. (Dans ce cas le premier argument est le côté du carré, et le second la hauteur du prisme). Si trois arguments sont utilisés, la boîte est considérée comme un parallélépipède. Par exemple :
    print volBoite() doit donner le résultat : -1 (? indication d'une erreur).
    print volBoite(5.2) doit donner le résultat : 140.608
    print volBoite(5.2, 3) doit donner le résultat : 81.12
    print volBoite(5.2, 3, 7.4) doit donner le résultat : 115.44
  3. Définissez une fonction changeCar(ch,ca1,ca2,debut,fin) qui remplace tous les caractères ca1 par des caractères ca2 dans la chaîne de caractères ch, à partir de l'indice debut et jusqu'à l'indice fin, ces deux derniers arguments pouvant être omis (et dans ce cas la chaîne est traitée d'une extrémité à l'autre). Exemples de la fonctionnalité attendue :
    >>> phrase = 'Ceci est une toute petite phrase.'
    >>> print changeCar(phrase, ' ', '*')
    Ceci*est*une*toute*petite*phrase.
    >>> print changeCar(phrase, ' ', '*', 8, 12)
    Ceci est*une*toute petite phrase.
    >>> print changeCar(phrase, ' ', '*', 12)
    Ceci est une*toute*petite*phrase.
    >>> print changeCar(phrase, ' ', '*', fin = 12)
    Ceci*est*une*toute petite phrase.
    
  4. Définissez une fonction eleMax(liste,debut,fin) qui renvoie l'élément ayant la plus grande valeur dans la liste transmise. Les deux arguments debut et fin indiqueront les indices entre lesquels doit s'exercer la recherche, et chacun d'eux pourra être omis (comme dans l'exercice précédent). Exemples de la fonctionnalité attendue :
    >>> serie = [9, 3, 6, 1, 7, 5, 4, 8, 2]
    >>> print eleMax(serie)
    9
    >>> print eleMax(serie, 2, 5)
    7
    >>> print eleMax(serie, 2)
    8 
    >>> print eleMax(serie, fin =3, debut =1)
    6
    

Solution

  1. def volBoite(x1 =10, x2 =10, x3 =10):
        "Volume d'une boîte parallélipipédique"
        return x1 * x2 * x3
    
    # test :
    print volBoite()
    print volBoite(5.2)
    print volBoite(5.2, 3)
    
  2. def volBoite(x1 =-1, x2 =-1, x3 =-1):
        "Volume d'une boîte parallélépipédique"
        if x1 == -1 :
            return x1           # aucun argument n'a été fourni
        elif x2 == -1 :
            return x1**3        # un seul argument -> boîte cubique
        elif x3 == -1 :
            return x1*x1*x2     # deux arguments -> boîte prismatique
        else :
            return x1*x2*x3
    
    # test :
    print volBoite()
    print volBoite(5.2)
    print volBoite(5.2, 3)
    print volBoite(5.2, 3, 7.4)
    
  3. def changeCar(ch, ca1, ca2, debut =0, fin =-1):
        "Remplace tous les caractères ca1 par des ca2 dans la chaîne ch"
        if fin == -1:
            fin = len(ch)
        nch, i = "", 0            # nch : nouvelle chaîne à construire
        while i < len(ch) :
            if i >= debut and i <= fin and ch[i] == ca1:
                nch = nch + ca2
            else :
                nch = nch + ch[i]
            i = i + 1
        return nch
    
    # test :
    print changeCar("Ceci est une toute petite phrase", " ", "*")
    print changeCar("Ceci est une toute petite phrase", " ", "*", 8, 12)
    print changeCar("Ceci est une toute petite phrase", " ", "*", 12)
    
  4. def eleMax(lst, debut =0, fin =-1):
        "renvoie le plus grand élément de la liste lst"
        if fin == -1:
            fin = len(lst)
        max, i = 0, 0
        while i < len(lst):
            if i >= debut and i <= fin and lst[i] > max:
                max = lst[i]
            i = i + 1
        return max
    
    # test :
    serie = [9, 3, 6, 1, 7, 5, 4, 8, 2]
    print eleMax(serie)
    print eleMax(serie, 2)
    print eleMax(serie, 2, 5)
    


À faire...link={{{link}}}

annotations[1]