1NSI : Cours Fonctions & Procédures. Modules⚓︎
Fonctions, Procédures & Routines⚓︎
Fonctions⚓︎
Une fonction (au sens de Python) est une séquence d'instructions (une succession continue de plusieurs lignes de codes), isolées (d'un certain point de vue) du reste du code, et qui renvoie en retour une valeur/un objet.
Procédures⚓︎
Une procédure (au sens de Python) est une séquence d'instructions (une succession continue de plusieurs lignes de codes), isolées (d'un certain point de vue) du reste du code, mais NE renvoyant PAS en retour de valeur/d'objet.
Routines⚓︎
Une routine est soit une fonction, soit une procédure.
Comment définir une fonction? une procédure?⚓︎
Comment définir une fonction?⚓︎
def nomFonction(parametres/arguments):
"""
Spécifications de la fonction:
ce que fait la fonction
le type des paramètres/arguments en entrée
le type des paramètres/arguments en sortie
"""
# Corps de la fonction qui réalise un certain traitement
return valeur
- Les définitions de fonctions se placent en haut du fichier contenant le script.
- Dans le cas d'une procédure, il ne doit y avoir AUCUN
return
- Dans le cas d'une fonction, Il PEUT y avoir plusieurs
return
dans le corps de la fonction. Dans ce cas, c'est le premierreturn
rencontré lors de l'exécution de la fonction qui fait sortir définitivement de la fonction. Dans ce cas, les autresreturn
ne seront donc jamais rencontrés durant cette exécutin particulière (mais ils le seront peut-être lors d'autres exécutions)
Notion de Type Hinting (depuis Python 3.5)⚓︎
Il est fortement préconisé/recommandé d'utiliser du
# TYPE HINTING
def carre(x:float)->float:
"""Fonction qui calcule le carré d'un nombre
x : float est un paramètre OBLIGATOIRE
"""
return x**2
Notion de Signature⚓︎
La return
?)
Comment définir une procédure?⚓︎
Idem mais sans le (sans aucun) return
# TYPE HINTING
def saluer(nom:str)->None:
"""Fonction qui salue quelqu'un
nom : str est un paramètre OBLIGATOIRE
"""
print("Bonjour ",nom," !")
Utilisation d'une fonction/procédure⚓︎
Une fonction, ou une procédure, N'est JAMAIS appelée AUTOMATIQUEMENT par l'algorithme, c'est-à-dire exécutée, SAUF si elle est spécifiquement appelée à une certaine ligne.
def saluer(nom:str)->None:
"""Fonction qui salue quelqu'un
nom : str est un paramètre OBLIGATOIRE
"""
print("Bonjour ",nom," !")
# ICI, AUCUN APPEL DE LA PROCÉDURE...
La procédure saluer()
N'est jamais appelée, donc jamais exécutée (le code à l'intérieur n'est jamais exécuté)
Ci-dessous, la procédure saluer()
est appelée
def saluer(nom:str)->None:
"""Fonction qui salue quelqu'un
nom : str est un paramètre OBLIGATOIRE
"""
print("Bonjour ",nom," !")
# REMARQUE : Une procédure ne renvoie AUCUNE valeur,
# donc il n'y a rien/aucune valeur à stocker lors de son appel...
# APPEL DE LA PROCÉDURE saluer()
saluer('Pauline')
def carre(x:float)->float:
"""Fonction qui calcule le carré d'un nombre
x : float est un paramètre OBLIGATOIRE
"""
return x**2
# ICI, AUCUN APPEL DE LA FONCTION carre()...
La fonction carre()
N'est jamais appelée, donc jamais exécutée.
Ci-dessous, la procédure saluer()
est appelée
def carre(x:float)->float:
"""Fonction qui calcule le carré d'un nombre
x : float est un paramètre OBLIGATOIRE
"""
return x**2
# Le résultat d'une fonction DOIT être stocké dans une variable
# car une fonction renvoie TOUJOURS une valeur
resultat = carre(2)
print("Résultat : {}".format(resultat))
Paramètres des fonctions⚓︎
Sans arguments/paramètres⚓︎
Une fonction PEUT n'admettre AUCUN paramètre/argument.
def saluer():
"""Fonction qui salue"""
print("Bonjour")
saluer()
Ici, la fonction saluer()
est bien appelée (après sa définition)
un argument OBLIGATOIRE⚓︎
def saluer(nom:str)->None:
"""Fonction qui salue quelqu'un
nom : str est un paramètre OBLIGATOIRE
"""
print("Bonjour {}".format(nom))
# bonjour() provoque une erreur :
# TypeError: bonjour() missing 1 required positional argument: 'nom'
saluer("Laura")
Plusieurs arguments OBLIGATOIRES⚓︎
def somme(a:float,b:float)->float:
"""Fonction qui calcule la somme de deux nombres
a : float est un paramètre OBLIGATOIRE
b : float est un paramètre OBLIGATOIRE
"""
return a+b
resultat = somme(2,3)
print("Résultat : {}".format(resultat))
arguments avec valeurs par défaut⚓︎
def bonjour(prenom,age=18):
"""Procédure qui salue une personne par son prénom et son âge
prenom : str est un paramètre OBLIGATOIRE
age : int est un paramètre AVEC UNE VALEUR PAR DÉFAUT 18
"""
print("Bonjour {}, vous avez {} ans".format(prenom,age))
bonjour("marie")
bonjour("paul",29)
Un nombre variable d'arguments avec *args
⚓︎
La syntaxe *args
(on peut remplace args
par le nom que vous souhaitez), permet d'indiquer, lors de la définition d'une fonction, que notre fonction peut accepter un nombre variables d'arguments.
Ces arguments args
sont passés sous forme d'un tuple
def somme(*valeurs):
s = 0
for valeur in valeurs:
s += valeur
return s
resultat1 = somme(2,3)
resultat2 = somme(2,3,4)
resultat3 = somme(2,3,4,5)
print("Résultat 1 : {}".format(resultat1))
print("Résultat 2 : {}".format(resultat2))
print("Résultat 3 : {}".format(resultat3))
Un nombre variable d'arguments avec **kwargs
⚓︎
La syntaxe **kwargs
(on peut remplace kwargs
par le nom que vous souhaitez), permet d'indiquer, lors de la définition d'une fonction, que notre fonction peut accepter un nombre variables d'arguments, mais cette fois-ci les arguments devront être passés sous la forme d'un dictionnaire Python: Ces arguments kwargs
sont passés sous forme d'un dict
def personne(**caracteristiques):
for i,j in caracteristiques.items():
print(i,j)
personne(prenom="Angelina",age=29)
personne(nom="Brad",age=31)
items()
qui permet de faire du tuple-unpacking
c'est-à-dire de récupérer les différentes paires clés-valeurs d'un dictionnaire.
Séparer les données afin de les passer à une fonction⚓︎
Les syntaxes *args
et **kwargs
peuvent être utilisées pour réaliser les opérations inverses de celles présentées ci-dessus, c'est-à-dire séparer des données regroupées dans un conteneur pour les passer séparéement à la fonction.
def somme(a,b,c):
s = a+b+c
return s
x = [2,4,5]
resultat = somme(*x)
print("Résultat : {}".format(resultat))
Fonctions anonymes lambda
⚓︎
Définir une fonction lambda
⚓︎
Python permet la définition de mini-fonctions, définies à la volée, en une seule ligne, sans leur donner de noms particulier.
>>> lambda x: 2*x
<function __main__.<lambda>(x)>
prouve que la fonction lambda, c'est-à-dire une fonction sans nom, a bien été créér donc définie, mais elle n'a PAS été appelée.
Ceci est l'équivalent de la notation mathématique suivante:
\(x\mapsto 2x \quad\) comprendre "la fonction qui à \(x\) associe \(2x\)".
Appeler une fonction lamda
⚓︎
méthode 1: stocker la fonction lambda
dans une variable⚓︎
>>> f = lambda x: 2*x
>>> f(2)
4
>>> f(3)
6
On a ainsi:
* stocké une fonction sans nom dans la variable f
, puis
* appelé f
comme d'habitude, avec un argument pour x
méthode 2: appel direct de lambda
avec des ()
⚓︎
>>> (lambda x:x*2)(3)
6
Variables Locales vs variables Globales⚓︎
Variables locales⚓︎
Les variables définies à l'intérieur d'une fonction n'existent, donc ne sont accessibles, qu'à l'intérieur de cette fonction:
def f(x):
a = 2
return 2*x
resultat = f(3)
print("Résultat = ",resultat)
print("a = ",a)
Dans l'exemple précédent, la variable a
n'existe qu'à l'intérieur de la fonction f
. La ligne 6 renvoie donc l'erreur suivante : NameError: name 'a' is not defined
On dit dans ce cas que :
* a
est une variable locale, et/ou que
* la variable a
admet une portée locale (/ un scope :uk: local)
La portée ou le scope :uk: d'une variable locale est un espace de noms restreint à la fonction, par opposition à l'espace de noms global (qui contient des noms d'objets définis globalement, au niveau de l'ensemble de l'algorithme).
L'espace de noms d'une fonction contient donc les variables locales, ainsi que le nom des paramètres définissant la fonction.
Les variables locales sont détruites après l'appel de la fonction. (ramasse miettes / garbage collector)
Variables Globales⚓︎
L'algorithme précédent prouve qu'une variable locale n'est pas accessible depuis l'extérieur de la fonction. Selon les contextes, cela peut être considéré comme une qualité, ou comme un problème :
Comment résoudre ce problème ?⚓︎
Dans le corps d'une fonction, on peut utiliser le mot-clé global
pour définir une variable en tant que variable globale, au lieu d'être définie comme variable locale, comme cela devrait être le cas par défaut.
On dit que la variable admet une portée globale (/un scope global :uk: )
def f(x):
global a
a = 2
return 2*x
resultat = f(3)
print("Résultat = ",resultat)
print("a = ",a)
Champ Global accessible depuis le Champ Local⚓︎
Une variable définie dans le champ global, existe également dans le champ local (à manipuler avec précaution):
def f(x):
print("a = ",a)
return 2*x
# A L'EXTERIEUR DE LA FONCTION
a=2
resultat = f(3)
print("Résultat = ",resultat)
# affiche bien "a=2" dans le corps de la fonction
Conflits Global vs Local⚓︎
En cas de conflit potentiel, entre une variable globale et une variable locale portant le même nom, c'est la portée de la variable qui résout le problème: * Dans le champ local (c'est-à-dire dans le corps de la fonction), la variable en doublon est vue comme une variable locale * Dans le champ global, la variable en doublon est vue comme une variable globale Il n'y a donc pas de conflits.
Modules⚓︎
Création de Modules⚓︎
Un module
est un fichier python en .py
ne contenant QUE des définitions de fonctions/procédures, éventuellement des constantes, destinées à être utilisées ailleurs, comme par exemple dans d'autres fichiers.
"""
nom de ce Fichier : 'monModule.py'
Module inutile qui affiche des bonjours internationaux :)
"""
# CONSTANTES
PI = 3.141592653
# FONCTIONS
def bonjour(nom:str)->str:
"""Dit Bonjour."""
return "Bonjour " + nom
def ciao(nom:str)->str:
"""Dit Ciao."""
return "Ciao " + nom
def hello(nom:str)->str:
"""Dit Hello."""
return "Hello " + nom
Méthodes d'import de Modules⚓︎
Pour utiliser le module monModule
:
* dans un interpréteur Python
* ou bien dans un (autre) fichier Python
Tous les exemples qui suivent, contiennent des codes qui ont été placés dans un fichier test.py
lui-même placé dans le même dossier que 'monModule.py'
# Import uniquement de la fonction 'bonjour()' du module 'monModule'
from monModule import bonjour
bonjour("Paul")
# Import uniquement de la fonction 'bonjour()' du module 'monModule'
from monModule import bonjour, ciao
bonjour("Paul")
ciao("Paula")
# Import de toutes les fonctions du module 'monModule'
from monModule import *
bonjour('Karl')
ciao('Bella')
hello('John')
# Import de toutes les fonctions du module 'monModule' d'une autre manière
import monModule
monModule.bonjour('Karl')
monModule.ciao('Bella')
monModule.hello('John')
# Import de toutes les fonctions du module 'monModule' avec un alias
import monModule as mod
mod.bonjour('Karl')
mod.ciao('Bella')
mod.hello('John')