Les fonctions

Ce document est extrait de notre cours de python

Une fonction est une boîte étanche avec une étiquette dessus (son nom), et qui contient des instructions. On peut appeler cette boîte pour exécuter les instructions qu'elle contient.

Pour créer une fonction (la définir), on utilise le mot clef def, suivi du nom de la fonction, puis de () et d'un :. Le code contenu dans la fonction est le code indenté en dessous.

Le nom d'une fonction doit :

# définition d'une fonction appelée hello
def hello():
    print("Bonjour ...")
    print("        ... le monde")

# en dehors de la fonction

Pour exécuter le code contenu dans la fonction (= appeler la fonction), on écrit son nom, suivi de parenthèses.

hello()
Bonjour ...
        ... le monde
print(".................")
hello()
print("=================")
.................
Bonjour ...
        ... le monde
=================
# Une fonction peut appeler une autre fonction
def presentation():
    print("Attention je vais parler :")
    hello()
    print("C'est tout pour moi, merci.")
    
    
# Appel de la fonction présentation
print(".....................")
presentation()
print("=====================")
.....................
Attention je vais parler :
Bonjour ...
        ... le monde
C'est tout pour moi, merci.
=====================
def printx():
    x = "coucou"
    print(x)
    
printx()
print(x)
coucou
Traceback (most recent call last):
  File "<basthon-input-8-dd2d8e0d38a0>", line 6, in <module>
    print(x)
          ^
NameError: name 'x' is not defined

Une fonction peut renvoyer un résultat avec le mot clef return

def monnombre():
    print("Je vous renvoie un nombre")
    return 42

x = monnombre()
print(x)
Je vous renvoie un nombre
42
# Le return termine directement l'exécution de la fonction
def monnombre():
    print("Je vous renvoie deux nombres")
    return 42
    return 12

x = monnombre()
print(x)
Je vous renvoie deux nombres
42

Une fonction peut accepter des paramètres (ou arguments) en entrée. Chaque paramètre a un nom. On les définit dans les parenthèses lors de la définition de la fonction.

def commentaire_age(age):
    if age < 18:
        print("Trop jeune")
    elif age < 70:
        print("Bonjour")
    else:
        print("Trop vieux")

commentaire_age(22)
Bonjour
def affine(x,a,b):
    return a*x+b

print(affine(1, 4, 5))
9

On peut donner les arguments d'une fonction par position. On peut aussi donner ces arguments par nom.

print(affine(x=1, a=4, b=5))
# Avantage : on peut les donner dans le désordre
print(affine(a=4, b=5, x=1))
9
9
# On peut mixer : par position et par nom.
# Seule contrainte : les arguments par position sont d'abord, puis ceux par nom
print(affine(1, b=5, a=4))
9

On peut rendre certains paramètres optionnels en leur donnant une valeur par défaut.

def affine(x, a, b=13): # si b n'est pas fourni, alors il faut le mettre à la valeur 13
    return a*x+b

# Par position
print(affine(1,4))
# Par nom
print(affine(x=1, a=4))
# En mixant
print(affine(1, a=4))
17
17
17
# Il faut lire les erreurs
affine(x=3)
Traceback (most recent call last):
  File "<basthon-input-23-cd34c49fe55d>", line 2, in <module>
    affine(x=3)
TypeError: affine() missing 1 required positional argument: 'a'
affine(a=9, 1)
  File "<basthon-input-24-715699b7c579>", line 1
    affine(a=9, 1)
                 ^
SyntaxError: positional argument follows keyword argument
# Exemple de fonction : cafe
def cafe(source=0, force=0, sucre=0):
    """ Affichage de la machine à café :
    
    affiche la chaine de caractère correspondant au café choisi
    
    Arguments :
    - source: 0 = grains, 1 = soluble
    - force: 0 = court, 1 = long, 2 = extra long
    - sucre: 0 = sans, 1 = sucré, 2 = très sucré
    """
    if source == 0:
        print("Café en grains", end=" ")
    else:
        print("Café soluble", end=" ")
    
    if force == 0:
        print("court", end=" ")
    elif force == 1:
        print("long", end=" ")
    else:
        print("extra long", end=" ")
    
    if sucre == 0:
        print("sans sucre")
    elif sucre == 1:
        print("sucré")
    else:
        print("trop sucré")

        
cafe(source=1, force=2, sucre=2)
cafe()
cafe(1,1,1)
Café soluble extra long trop sucré
Café en grains court sans sucre
Café soluble long sucré
def code(secret):
    if secret == "supercode":
        return "entrez"
    else:
        return "interdit"
    
print(code("supercode"))
entrez
# Possible aussi d'écrire :
def code(secret):
    if secret == "supercode":
        return "entrez"
    return "interdit"

Petit retour sur l’étanchéité des fonctions

:::

L'étanchéité des fonctions est "relative"...

a = 15
def fonction(b):
    print(a*b) # La valeur de a est lue / récupérée en dehors de la fonction

fonction(5)
75
a = 15
def fonction(b):
    print(a*b) # Ça ne fonctionne plus car il existe dans la fonction une variable locale a
    a = 1
    return a

fonction(5)
Traceback (most recent call last):
  File "<basthon-input-18-915c85b6371c>", line 7, in <module>
    fonction(5)
  File "<basthon-input-18-915c85b6371c>", line 3, in fonction
    print(a*b) # Ça ne fonctionne plus car il existe dans la fonction une variable locale a
          ^
UnboundLocalError: cannot access local variable 'a' where it is not associated with a value
a = 15
def fonction():
    a = a + 1

fonction()
print(a)
Traceback (most recent call last):
  File "<basthon-input-19-71f2b5ac3b57>", line 5, in <module>
    fonction()
  File "<basthon-input-19-71f2b5ac3b57>", line 3, in fonction
    a += 1
    ^
UnboundLocalError: cannot access local variable 'a' where it is not associated with a value
a = 15
def fonction():
    global a
    a = a + 1

fonction()
print(a)
16

Le mieux c'est de toujours conserver l'étanchéité parfaite des fonctions :