Aller au contenu

Fonctions impératives

On peut créer des fonctions avec des séquences d'instructions :

def moyenne(x, y, z):
    """x, y, z des nombres,
    retourne la moyenne de x, y et z
    """
    somme = x + y + z
    return somme / 3

Variables locales

Quand on définit des variables dans une fonction, ces variables n'existent que dans la fonction.

def f(x):
    a = 5
    return x * a

a = 3
print("a avant f(5) vaut", a)
print("f(5) vaut", f(5))
print("a après f(5) vaut", a)

Affiche

a avant f(5) vaut 3
f(5) vaut 25
a après f(5) vaut 3

La valeur de a dans notre programme n'a pas changé, même si dans l'appel à f, on a fait a = 5.

C'est parce que a dans f n'est pas le même a que celui du corps de notre programme. On appelle celà les variables locales, ou contexte local d'une fonction.

Arguments et variables

Quand on passe des variables en argument à une fonction, c'est l'ordre qui compte et non le nom des variables.

def f(x, y):
    return 2 * x + y

x = 1
y = 2
print(f(y, x))

Affiche

5

Pour évaluer

f(y, x)

Python applique les étapes suivantes.

1) Python remplace les variables par leur valeurs.

f(y,x) devient f(2, 1)

2) Python remplace alors les paramètres de la fonction par les valeurs, dans le même ordre.

def f(x, y):
    return 2 * x + y

devient

def f(2, 1):
    return 2 * 2 + 1

3) Python effectue le calcul

def f(2, 1):
    return 2 * 2 + 1

devient

def f(2, 1):
    return 5

4) L'appel est remplacé par la valeur retourné

f(y, x)

devient

5

Impureté

Les fonctions en Python peuvent parfois modifier l'état du programme en dehors de leur état local.

L'affichage dans la console est un exemple d'une telle modification externe. On parle alors d'état global.

def afficher_et_additionner(x, y):
    print("x:", x, "y:", y)
    return x + y

v = afficher_et_additionner(2, 3)
print(v)

Ce programme affiche

x:2 y:3
5

Dans ce programme, on ne peut pas remplacer la fonction par sa valeur de retour sans changer le comportement du programme :

v = 5
print(v)

Afficherait uniquement

5

On dit donc que la fonction afficher_et_additionner est impure, par oppositions aux fonction mathématiques, pures que nous avons vues plus tôt.

Les fonctions impures sont parfois une bonne solution, mais elles ont tendance à rendre l'analyse du code plus difficile, puisqu'il faut prendre en compte leur effets hors contexte local, appelés effets de bords.

On va donc essayer de faire des fonctions qui sont le plus pures possibles, c'est à dire qui n'ont aucun impact en dehors de leur contexte local. Les print nous serviront donc majoritairement à étudier le comportement de nos programmes en affichant des valeurs à un moment donné.

Exercice

Voici deux fonctions :

def f_a(x):
    print("a")
    return x+2

def f_b(x):
    print("b")
    return x * 2

Voici deux programmes. Expliquez en quoi ils n'ont pas le même comportement.

v = f_a(2) + f_b(3)
print(v)
v = f_b(3) + f_a(2)
print(v)

Peut-être que l'ordre d'évaluation de l'expression a de l'importance...

Les fonctions f_a et f_b font toutes deux un affichage en console. L'ordre dans lesquelles elles sont evaluées dans les expressions f_a(2) + f_b(3) et f_b(3) + f_a(2) aura donc une influence sur le comportement du programme.

v = f_b(3) + f_a(2)
print(v)

affiche

b
a
10

Alors que

v = f_a(2) + f_b(3)
print(v)

affiche

a
b
10

Les stations ...

Exercice

A l'aide de la fonction station_compatible, ecrivez un programme qui affiche, pour chaque distance entre 100 et 110 millions de kms, si une station ayant pour irradiance min 2000 et pour irradiance max 3000 est compatible avec cette distance.

Code fonction station compatible
def irradiance(r):
    return (5535.8/r)**2

def station_compatible(ir_min, ir_max, distance):
    """ir_min, ir_max les irradiances minimales et maximales que peut supporter la stations, en watts par mètre carré.
    distance la distance au soleil, en millions de kilomètres

    >>> station_compatible(9800, 12000, 125)
    False

    >>> station_compatible(2000, 3000, 120)
    True

    >>> station_compatible(1000, 2000, 120)
    False
    """
    return ir_min <= irradiance(distance) <= ir_max

Exemple d'affichage :

False
False
True
True
True
True
True
True
True
True
True

Il vous faut appeler plusieurs (11 !) fois la fonction dans un fichier ... N'hésitez pas à faire des copiers-coller.

def irradiance(r):
    return (5535.8/r)**2

def station_compatible(ir_min, ir_max, distance):
    """ir_min, ir_max les irradiances minimales et maximales que peut supporter la stations, en watts par mètre carré.
    distance la distance au soleil, en millions de kilomètres

    >>> station_compatible(9800, 12000, 125)
    False

    >>> station_compatible(2000, 3000, 120)
    True

    >>> station_compatible(1000, 2000, 120)
    False
    """
    return ir_min <= irradiance(distance) <= ir_max

#Le programme en question commence ici
print(station_compatible(2000, 3000, 100))
print(station_compatible(2000, 3000, 101))
print(station_compatible(2000, 3000, 102))
print(station_compatible(2000, 3000, 103))
print(station_compatible(2000, 3000, 104))
print(station_compatible(2000, 3000, 105))
print(station_compatible(2000, 3000, 106))
print(station_compatible(2000, 3000, 107))
print(station_compatible(2000, 3000, 108))
print(station_compatible(2000, 3000, 109))
print(station_compatible(2000, 3000, 110))