@ccueil Colles

Fonctions en python

Définition, utilisation et autre…




Une fonction est une structure qui contient un ensemble d'instructions. Un simple appel à la fonction, à chaque fois que souhaité permet de (re)lancer toutes ses instructions.
Une fonction peut accepter des arguments, ou variables, en entrée, et de même en renvoyer ou non en sortie.

Définition d'une fonction

Syntaxe générale

En python, la définition se fait via le mot clé def:
def nom_fonction(arg1,arg2,…):
    instruction 1
    instruction 2
    …
L'indentation définit, comme partout en python, le corps de la fonction. Par exemple,
def AfficheOK():
    print("OK, tout va bien")
définit une fonction dont le nom est AfficheOK, qui n'accepte pas d'argument en entrée et qui, une fois appelée, affiche le texte "OK, tout va bien".
Cette fonction ne renvoyant aucune valeur s'appelle aussi dans la terminologie de la programmation une routine.
Cette fonction s'utilise simplement en l'appelant grâce à son nom, à chaque fois que souhaité, après sa défintion.
AfficheOK()
qui affiche donc OK, ….
Les parenthèses sont obligatoires lors de l'appel de la fonction, même si elles sont vides, comme ici, en l'abscence d'arguments.

Argument d'entrée

On peut définir des fonctions qui dépendent, donc agissent différemment selon, de paramètres. Par exemple,
def AfficheOK(txt):
    print("OK, tout va ",txt)
s'utilise suivant
AfficheOK("bien")
# affiche: OK, tout va bien
AfficheOK("mal")
# affiche: OK, tout va mal
AfficheOK(3)
# affiche: OK, tout va 3
Par contre maintenant l'appel de la fonction sans argument renvoie une erreur:
AfficheOK()
#TypeError: AfficheOK() takes exactly 1 argument (0 given)
qui nous rappelle ce que l'on sait ici déjà…
Voir un peu plus loin pour la définition et l'utilisation de fonctions avec des valeurs par défaut.

Argument de sortie

On peut bien sûr demander aussi à une fonction de nous renvoyer le résultat de calculs, par exemple
def f(x):
    y=3*x*x-5
    return y
définit une fonction f qui prend un argument x en entrée, effectue un calcul à partir de celui-ci, puis renvoie le résultat de ce calcul.
print(f(3))
# affiche: 7
y=f(5)
print(y)
# affiche: 70
y=f(-2)
z=2*y+3
print(z)
# affiche: 17
Une telle fonction, avec exactement un argument numérique en entrée et qui renvoie une valeur numérique en sortie, est une fonction mathématique telle que définie et vue au lycée.

On n'est pas limité aux valeurs numériques, et on peut utiliser toutes les opérations et structures permises par python dans le corps d'une fonction. Par exemple, en reprenant la fonction AfficheOK() précédente, on peut faire un traitement conditionnel suivant l'argument d'entrée
def AfficheOK(txt):
    if(txt=="bien"):
        y="OK, tout va bien"
    elif(txt=="mal"):
        y="Mal, tout va mal"
    else:
        y="Bof, c'est pas clair"
    return y

y=AfficheOK("bien")
print(y)
# affiche: OK, tout va bien
y=AfficheOK("mal")
print(y)
# affiche: Mal, tout va mal
y=AfficheOK(3)
print(y)
# affiche: Bof, c'est pas clair
On sort bien sûr là des fonctions mathématiques numériques du lycée.

Fonction avec plusieurs argument

On peut définir des fonctions qui acceptent plusieurs argument en entrée, par exemple
def f(x,y):
    z=x*y
    return z

z=f(2,3)
# z vaut maintenant 6
Ces multiples arguments ne sont d'ailleurs pas forcément du même type:
def AfficheOK(a,txt):
    print(a*txt)

AfficheOK(3,"zut ")
# Affiche: zut, zut, zut

De même en sortie, une fonction peut renvoyer plusieurs valeurs
def f(x,y):
    z=2*x+y
    w=-x-y
    return z, w

print(f(1,2)) # affiche: (4,-3)
z,w=f(2,3) # donc z=7 et w=-5
print(z,w,z+w) # affiche: 7 -5 2

Fonctions avec des valeurs par défaut

Il est parfois utile de définir des fonctions avec plusieurs paramètres dont certains, parce que par exemple rarement modifiés, sont optionels et possèdent donc une valeur par défaut. Par exemple
def f(x,y=0,z=1):
    r=x+y+z
    return r

print(f(1,2,3)) # affiche: 6
print(f(1,2)) # ici, z=1 et on affiche: 4
print(f(1)) # ici y=0 et z=1 donc on affiche: 2
On peut donc ici ne pas fournir les arguments y et/ou z qui, dans ce cas, prennent leur valeur par défaut.
Comment faire alors si on veut donner une valeur à z, autre que 1, et laisser la valeur par défaut de y ?
En effet, l'ordre des variables est en général fondamental, avec la fonction précédente,
def f(x,y,z=0):
    return 2*x+y-z
print(f(1,2)) # affiche: 4
print(f(2,1)) # affiche: 5
Python accepte que l'on spécifie les variables avec leur nom (ou étiquette), permettant alors d'utiliser un ordre quelconque:
def f(x,y,z=0):
    return 2*x+y-z
print(f(1,2)) # affiche: 4
print(f(x=1,y=2)) # équivalent à la forme précédente et affiche: 4
print(f(y=2,x=1)) # équivalent aussi à la forme précédente et affiche: 4
print(f(y=0,x=10)) # affiche: 20
print(f(z=5,x=2,y=0)) # affiche: -1

Définition récursive

L'exemple le plus connu est celui de la fonction factorielle:
def fact(n):
    if n==0: return 1
    elif n>=1: return n*fact(n-1)

print(fact(4)) # affiche: 24
On peut (et doit…) améliorer cette fonction pour répondre à un utilisateur quelque soit la valeur de l'argument n fourni:
def fact(n):
    if isinstance(n,int): 
        if n==0: return 1
        elif n>=1: return n*fact(n-1)
        else: print("Erreur:",n,"<0")
    else:
        print("Erreur:",n,"n'est pas un entier")
print(fact(4)) # affiche: 24
print(fact(-3)) # affiche: Erreur: -3 <0
print(fact(4.1)) # affiche: Erreur: 4.1 n'est pas un entier
print(fact(4.0)) # affiche: Erreur: 4.0 n'est pas un entier


Définition d'une fonction dans une fonction (encapsulation)

On peut encapsuler des fonctions, c'est-à-dire définir une fonction dans laquelle sont définies une, ou plusieurs, autres fonctions.
Dans l'exemple ci-dessous, on définit une fonction avec un paramètre. La fonction à l'extérieur, h, permet de fixer le paramètre de la fonction i à l'intérieur.
def h(d):
    def i(x):
        return x*d
    return i

i=h(4)
print(i(3), i(5)) # affiche: 12  20

k=h(-4)
print(k(3), k(5)) # affiche: -12 -20

Localisation des variables: espaces de travail, variables locales et globales

Avec python, on travaille dans un espace de travail dans lequel sont définis un ensemble de variables, de fonctions, objets et méthodes. On peut de plus y définir d'autres variables, fonctions…
Chaque fonction définie dans cet espace définit aussi son propre espace de travail local, dans lequel on peut aussi définir des variables, fonctions…
Ces espaces sont imbriqués et il est important de connaître les liens possibles entre eux.
A=3 #définition de la variable A dans l'espace de travail global

def f(x):
    A=1
    z=x+A
    return z

print(f(3)) # affiche 4
print("A=",A) # affiche A= 3

def g(x):
    z=x+A
    B=7
    return z

print(g(3)) # affiche 6
print("A=",A) # affiche A= 3
print(B) # NameError: name 'B' is not defined
Espace global
Variable A
Fonctions f, g
Espace local: fonction f  
Variables A, x, z

Espace local: fonction g  
Variables x, z, B
Dans l'espace global, les variables des espaces locaux ne sont pas connues. De plus, à la fin de l'exécution d'une fonction, l'espace local de celle-ci est simplement effacé. Dans l'exemple précédent, la variable B est donc inconnue dans l'espace global, et hors du corps de la fonction g son utilisation amène une erreur.
À partir d'un espace de travail, on ne peut pas modifier les variables d'un espace supérieur. L'utilisation et la modification d'une variable n'affecte pas les autres espaces: la modification de A dans f ne change pas la valeur de A dans l'espace dans l'espace global, à moins d'utiliser des variables définies globalement, voir ci-dessous.
Par contre, si une variable rencontrée n'existe pas dans l'espace dans lequel elle est utilisée, python cherche dans l'espace global qui le contient, puis éventuellement dans l'espace global de niveau supérieur…
a=1
def f():
    c=5
    def g(x):
        return x+c
    def h(x):
        return x+a
    return g,h

g,h=f()
print(g(1)) # affiche 6
print(h(1)) # affiche 2
Espace global
Variable a
Fonction f
Espace local: fonction f
Variable c
fonctions g, h

Espace local: fonction g
Variable x
Espace local: fonction h Variable x


Localisation des objets et fonctions

Si dans une fonction on ne peut modifier la valeur d'une variable d'un autre espace de travail (sans l'utilisation explicite de variables globales, voir ci-dessous), on peut par contre appliquer des méthodes à des objets, les modifiant donc éventuellement, à partir d'une fonction, par exemple:
a=[1,2,3]
def f():
    a.append(4);

print(a) # affiche: [1, 2, 3]
f() # appel de la fonction f
print(a) # affiche: [1, 2, 3, 4]


Variables globales

Dans un espace de travail, python peut accéder aux variables des espaces qui le contiennent, mais ne peut pas les modifier. La façon la plus adaptée d'accéder à des variables et les modifier, et de les utiliser en arguement d'entrée de la fonction, et/ou de les retourner en fin de fonction (via return); les fonctions sont faites pour cela exactement, lire des variables, effectuer des instructions les modifiant, et retourner les résultats.
Néanmoins, on peut quand même utiliser et modifier des variables d'un espace de travail de niveau supérieur en spécifiant que la variable en question est globale:
a=1
def f(x):
    global a
    a=2
    return 2*x

print("a=",a) # affiche a= 1
y=f(3) # exécute la fonction f, et y=6
print("a=",a) # affiche maintenant a= 2

Exercices et QCM


Programmation en python