Sous-programme : fonction, procédure¶
version 2017, PhL.
Table of Contents¶
Les fonctions de ... Monsieur Jourdain !¶
Fonctions mathématiques : trigonométriques, logarithmes, exponentielle, puissances ...
Est caractérisée par
- son nom :
cos(...)
- ses arguments d'entrée : $\pi$/3
- une valeur de retour (résultat, destination) : écran, une variable résultat
c
, le terme d'une expression :cos(pi/3)**2 + sin(pi/3)**2
Boites noires :
- spécification = ce que ça fait : OK
- implémentation = comment ça le fait : ??
Exemple¶
from math import cos, pi
c = cos(pi/3)
print(c)
-
Ligne 1 : fonction
cos
et valeurpi
disponibles -
Ligne 2 : appel de la fonction
cos(...)
l'argument effectifpi/3
. -
Ligne 2 : valeur-résultat affectée dans la variable
c
-
Ligne 3 : affichage de la valeur retournée
Rmq. : précision numérique ?
from math import *
c = cos(pi/3)
s = sin(pi/3)
un = c*c + s*s
print("cos*cos + sin*sin = ", un)
Vocabulaire :¶
- python : fonction à la place de sous-programme
- argument ou paramètre
Pourquoi des fonctions¶
- Eviter de ré-écrire
- Simplifier la lecture donc la compréhension
- Ré-utiliser l'existant
- Découper un processus compliquées en une suite d'étapes plus simples : modularité
- Découpage appliqué récursivement : cad appliqué pour chaque étape jusqu'à que ce soit assez simple !
Exercice :¶
Algorithme synthétique qui affiche :
Carcassonne est la préfecture du département 11
------------------------------------------------
Perpignan est la préfecture du département 66
------------------------------------------------
Montpellier est la préfecture du département 34
------------------------------------------------
Foix est la préfecture du département 09
------------------------------------------------
# Un peu synthétique : une boucle
for v,d in ("Carca", "11"), ("Perpi","66"), ("Montpel", "34"), ("Foix", "09"):
print(v, "est la préfecture du département", d)
print("------------------------------------------------")
# définition
def afficher_pref_dpt(ville, num_dpt):
print(ville, "est la préfecture du département", num_dpt)
print("------------------------------------------------")
# 4 appels
afficher_pref_dpt("Carca", "11")
afficher_pref_dpt("Perpi", "66")
afficher_pref_dpt("Montpell", "34")
afficher_pref_dpt("Foix", "09")
print()
# 4 appels synthétiques
for (v,d) in ("Carca", "11"), ("Perpi","66"), ("Montpell", "34"), ("Foix", "09"):
afficher_pref_dpt(v,d)
Définition et appels de fonction¶
Définition d'une fonction¶
Généralement :
- le nom de la fonction
- les arguments formels d'entrées : leurs nombres, leurs types, l'identificateur de chacun
- les sorties : leurs nombres, leurs types, l'identificateur de chacun
Python :
def nom(liste d'arguments formels):
... # le corps de la fonction
a = 17
b = 3.2
afficher_pref_dpt(a, b)
Appel d'une fonction¶
- le nom
- les arguments effectifs : les valeurs des arguments d'entrée
- les identifiants des variables de sortie
Le retour de valeur¶
-
Python : mot-clé
return
return valeur, variable, expression
return None
-
Termine l'exécution du corps de la fonction
- à la fin en général
- pas toujours : pas nécessairement unique
def doubler(u):
""" double la valeur entière u
Entrées : u (int)
Retourne int
"""
return 2*u
def tripler(u):
""" triple la valeur entière u
Entrées : u (int)
Retourne int
"""
v = 3*u
return v
def un():
return 1
# des appels
d = doubler(2)
t = tripler(2)
print(d, t)
res = un()
print('un =', res)
doubler(5.5)
On verra ça plus loin mais help()
est une fonction utile qui décrit ce que fait la fonction
help(doubler)
r = doubler(2)
a = 5
deux_a = doubler(a)
print(r, a, deux_a)
import math
#help(math)
doubler(math.pi)
# plus douteux hélas ...
doubler('a')
def afficher_pref_dpt(ville, num_dpt):
print(ville, "est la préfecture du département", num_dpt)
print("------------------------------------------------")
return None
# appel
afficher_pref_dpt("Carca", "11")
d = afficher_pref_dpt("Carca", "11")
print(d)
def tetu():
return 1
res = tetu() # appel et affectation du résultat
print('res = ', res) # affichage
# boucle d'appels à tetu() dans un print()
for i in range(5):
print('appel tetu:', tetu())
# appel sans affectation, ni print.
# L'interpréteur python affiche sa valeur en Out[..]
doubler(1)
Exemple avec plusieurs return¶
- Une fonction qui calcule et renvoit la valeur absolue d'un entier
- Une fonction
puissance
qui calcule et renvoit $x^n$ pour $n>0$- $x^n = x \times x^{n-1}$
- pas la peine de perdre trop de temps pour calculer $0^n = 0$
def val_abs(x):
''' calcule la valeur absolue du flottant x
entrée : x (float)
retourne float
'''
if x < 0:
return -x
else:
return x
a = -5.0
b = 3.3
z = val_abs(0.0)
ra = val_abs(a)
rb = val_abs(b)
print(z, ra, rb, val_abs(0.0))
Signature d'une fonction vs. corps d'une fonction¶
Vocabulaire : signature = en-tête = spécification
signature : décrit ce que fait la fonction
corps : décrit comment elle le fait
- Signature :
- nécessaire et suffisant pour utiliser la fonction (appel)
help(nom_f)
affiche la signature de la fonctionnom_f
- En quoi ça consiste ? il faut compléter la syntaxe python en explicitant
- rôle : une phrase
- pour chaque argument formel : son type, [valeur par défaut]
- le type du/des argument retourné
Exemple de signature :
def doubler(u):
""" double la valeur entière u
Entrées : u (int)
Retourne int
"""
Exemple de corps : il contient aussi la signature
def doubler(u):
""" double la valeur entière u
Entrées : u (int)
Retourne int
"""
return 2*u
Application et help(...) :
help(doubler)
Exemple signature, appel, corps et plusieurs arguments¶
def puissance(x, n):
'''
calcule x**n de façon itérative pour
x : float
n : entier positif
retourne float
'''
# corps de la fonction puissance
r = 1.0
for i in range(1,n+1):
r = r * x
return r
# appels avec des valeurs
mille = puissance(10.0, 3)
print("mille =", mille)
vrai_ou_faux = (puissance(3.1,2) == 3.1 * 3.1)
print(vrai_ou_faux)
# appels avec une variable
n = int(input("n premières puissances de 2 pour n = "))
for i in range(n):
print(puissance(2, i))
print("cas particulier")
print(puissance(2.0, 0))
# appels avec des variables
p = float(input("n premières puissances de p pour p = "))
n = int(input("et n = "))
for i in range(n):
print(puissance(p,i))
Ouvrons la boîte !¶
Variable locale vs. variable globale, portée des variables¶
Variable locale à une fonction : introduite dans le corps de la fonction pour permettre le traitement
Variable globale : définie dans le cadre appelant
Portée : zone où une variable est utilisable
# a est une variable globale
a = 15
print("a:", a)
# x est une variable locale à f
def f():
x = 1
print("dans f: ", x)
return x
r = f()
print("r=", r)
print("x=", x)
- Portée d'une variable locale limitée au corps de la fonction
- logique : déclaration, affectation, puis instructions, ..., return
- La portée d'une variable globale à l'intérieur d'une fontion varie en python
- utilisation de sa valeur = OK
- modification de sa valeur = NON (en général)
- déclaration avec
global
si besoin de modifier
a = 17
def f1():
print("a dans f1 (a pas locale):", a)
return None
def f2():
a = 1
print("a dans f2 (sans global) :", a)
return None
def f3():
global a # ainsi f3 accède à la variable de la ligne 1
a = 1
print("a dans f3 (avec global) :", a)
return None
#
print("a extérieur :", a)
f1()
print("a extérieur :", a)
f2()
print("a extérieur :", a)
f3()
print("a extérieur :", a)
#print(x)
Passage des arguments par valeur¶
Le corps de la fonction ne connait que les paramètres formels.
L'appel de la fonction définit les paramètres effectifs.
Comment le paramètre effectif devient-il connu par la fonction appelée ?
Qu'est-ce qui est connu de l'appelé ?
- la valeur du paramètre effectif ?
- la variable du paramètre effectif ? Se sont les questions du passage de paramètres appelant-appelé
Comment est transmis un argument effectif ?
- si c'est une valeur : ok
- si c'est une variable : valeur ? variable ?
Dépend des langages de programmation
python : passage par valeur
Explication :
- transmission de la valeur de l'argument effectif
- argument formel similaire à variable locale de la fonction
- à l'extérieur de la fonction : pas de modification de la variable passée en argument
u = 2
x = 5
def f(x):
''' incrémente x
entrée : x int
retourne int '''
r = x + 1
return r
def g(x):
x = x + 1
return x
print(f(u))
print(g(u))
print(u)
print()
print(f(x))
print(g(x))
print(x)
Exemple : une fonction de permutation de 2 entiers ... ?
a = 1
b = 11
print("avant : a,b =", a, b)
t = a
a = b
b = t
print("après : a,b =", a, b)
def permuter(x, y):
''' attention :
les print dans cette fonction sont uniquement à but pédagogique
'''
print("dans permuter, avant x,y :", x, y)
t = x
x = y
y = t
print("dans permuter, après x,y :", x, y)
return x, y
# marche pas !
a = 1
b = 11
print("avant fonction : a,b =", a, b)
permuter(a, b)
print("après fonction : a,b =", a, b)
Compléments¶
- Notion d'effet de bord
- pro/cons du passage par valeur
- fonction vs. procédure
- Vision logique du passage de paramètres : modes
in
,out
,in_out
Synthèse¶
- Fonction pour factoriser le traitement, structurer le déroulement d'un algo
- définition vs. appel
- signature vs. corps
- argument formel vs. effectif
- return vs. print
- portée d'une variable locale vs. portée d'une variable globale
- passage d'argument par valeur (python, non mutable)
Exercices en démonstration¶
- Fonctions min
- Ecrire la fonction min(a,b) : signature, appels, puis corps
- Proposer plusieurs écritures du corps : avec un seul return, avec deux, ...
- S'en servir pour écrire la fonction min(x, y, z) : signature, appels, puis corps
- Proposer plusieurs écritures du corps
- Géométrie du plan. Ecrire une fonction (signature puis corps) et un programme qui l'appelle pour résoudre chacun des problèmes suivants.
- je calcule la pente d'une droite définie par deux points dans le plan
- je calcule l'ordonnée d'un point situé sur une droite définie par sa pente et son ordonnée à l'origine
- je calcule l'ordonnée à l'origine d'une droite définie par deux points
- je vérifie si un point appartient ou non à une droite définie par deux points
- je calcule l'intersection de deux droites définies par deux paires de points en veillant à répondre dans tous les cas
def min(a, b):
'''retourne min(a,b)
entrées : a,b int
retourne int
-> version un seul return
'''
if a < b:
m = a
else:
m = b
return m
def min2(a, b):
'''retourne min(a,b)
entrées : a,b int
retourne int
-> version deux return
'''
if a < b:
return a
else:
return b
def min3a(a,b,c):
'''retourne min(a,b,c)
entrées : a,b,c int
retourne int
-> version 1 return, 2 appels à min(a,b)
'''
if min(a, b) < c:
m = min(a, b)
else:
m = c
return m
def min3b(a,b,c):
'''retourne min(a,b,c)
entrées : a,b,c int
retourne int
-> version 1 return, 1 appel à min(a,b)
'''
m_ab = min(a, b)
if m_ab < c:
m = m_ab
else:
m = c
return m
def min3(a,b,c):
'''retourne min(a,b,c)
entrées : a,b,c int
retourne int
-> version fonctionnelle : 2 appels imbriqués
'''
return min(min(a, b), c)
# des appels
x = 23
y = 44
z = 27
m_xyz = min3a(x, y, z)
print(m_xyz)
m_xyz = min3b(x, y, z)
print(m_xyz)
m_xyz = min3(x, y, z)
print(m_xyz)