Fonctions, modules et POO
Se connecter pour s'inscrireVotre progression
Syllabus
-
-
Objectifs
-
Validations de compétences
-
Public cible
Aucun public cible spécifié pour ce module.
-
Besoins techniques
-
Prérequis
- Aucun prérequis
-
Niveau
-
Historique du module
Aucune action enregistrée
Fonctions, modules et POO
-
Fonctions
En Python, une fonction est définie avec
def, les paramètres par défaut sont évalués à la définition, et la valeur de retour estreturn— unreturnsans valeur arrête la fonction et renvoieNone.def moyenne(notes: list[float], mention: str = "") -> float: """Calcule la moyenne et renvoie un message.""" if not notes: # évite la division par zéro raise ValueError("liste de notes vide") moyenne = sum(notes) / len(notes) if mention: return moyenne # type ignore return moyenne, mention # un tupleValeurs par défaut mutables : l'erreur classique
# MAUVAIS : la liste est créée une seule fois, partagée par tous les appels def ajouter(elt, cible=[]): cible.append(elt) return cible # BON : None par défaut, liste créée à chaque appel def ajouter(elt, cible=None): if cible is None: cible = [] cible.append(elt) return cibleArguments nommés et déballage
def afficher(nom, *, couleur="noir", taille=10): print(nom, couleur, taille) afficher("titre", couleur="rouge") # lisible, l'ordre n'importe plus premier, *reste, dernier = [1, 2, 3, 4, 5] # premier=1, reste=[2,3,4], dernier=5Le
*seul rend les paramètres suivants obligatoires et nommés : c'est une façon simple d'éviter les erreurs d'appel.Fonctions lambdas et closures
carre = lambda x: x * x # une seule expression def multiplier(facteur): def interne(x): return x * facteur # « capture » du facteur return interne double = multiplier(2) print(double(21)) # 42 -
Classes et objets
Une classe décrit des données et les méthodes qui les manipulent. Le constructeur est
__init__, et la méthode__repr__définit ce qui s'affiche.class CompteBancaire: """Compte avec solde contrôlé.""" def __init__(self, titulaire: str, solde: float = 0.0): self.titulaire = titulaire self._solde = solde # convention : attribut « privé » def deposer(self, montant: float) -> bool: if montant <= 0: return False self._solde += montant return True @property # accès en lecture def solde(self) -> float: return self._solde def __repr__(self) -> str: return f"Compte({self.titulaire}, {self._solde:.2f})"@propertytransforme une méthode en attribut en lecture seule :c.soldeau lieu dec.get_solde(), tout en gardant le contrôle. Une classedataclassévite d'écrire le constructeur à la main :from dataclasses import dataclass, field @dataclass class Etudiant: nom: str age: int cours: list[str] = field(default_factory=list) # pas de partage ! e = Etudiant("Alice", 22, ["Python"]) print(e) # Etudiant(nom='Alice', age=22, cours=['Python'])Héritage et polymorphisme
class Forme: def aire(self) -> float: raise NotImplementedError("à redéfinir") class Cercle(Forme): def __init__(self, rayon: float): self.rayon = rayon def aire(self) -> float: return math.pi * self.rayon ** 2 formes = [Cercle(1), Cercle(2)] print(sum(f.aire() for f in formes)) # la même méthode, des résultats différentsLa dernière ligne est le polymorphisme : le code ne connaît pas le type réel, il appelle
aire(). -
Modules, imports et décorateurs
Organiser le code
mon_projet/ ├── main.py ├── outils/ │ ├── __init__.py │ └── maths.pyImporter
from outils.maths import moyenne # une chose précise import outils.maths # le module entier from outils import maths # le sous-moduleOn importe un symbole précis plutôt qu'un module entier : on sait d'où vient chaque chose, et on évite les collisions de noms.
La bibliothèque standard
Avant d'écrire une fonction, vérifier si elle existe déjà :
math,datetime,json,pathlib,csv,random,itertools,collections,unittest.import json with open("config.json", encoding="utf-8") as f: config = json.load(f) # dict from pathlib import Path for fichier in Path("dossier").glob("*.txt"): print(fichier)Décorateurs
Un décorateur est une fonction qui enveloppe une autre fonction. Il sert à la journalisation, aux mesures de temps, aux permissions.
import functools import time def chronometrer(fonction): @functools.wraps(fonction) # garde le nom et la docstring def enveloppe(*args, **kwargs): debut = time.perf_counter() try: return fonction(*args, **kwargs) finally: duree = (time.perf_counter() - debut) * 1000 print(f"{fonction.__name__} : {duree:.1f} ms") return enveloppe @chronometrer def traitement(): ... -
Exercices
- Correction du bug : ce compteur d'appels est-il
correct ? Expliquez, puis corrigez.
def compter_appels(fonction): appels = [0] def enveloppe(*args, **kwargs): appels[0] += 1 return fonction(*args, **kwargs) return enveloppe - Catalogue : écrivez une classe
Article(nom, prix, quantité) avec une méthodetotal(), et une fonction qui renvoie le total d'une liste d'articles. - Décorateur : écrivez un décorateur
journalisequi affiche les arguments reçus avant l'appel.
- Correction du bug : ce compteur d'appels est-il
correct ? Expliquez, puis corrigez.