Lenaick Sorimoutou

Retour

9. Les fonctions avancées en Python

Approfondissez vos connaissances sur les fonctions Python : paramètres par défaut, fonctions lambda, décorateurs et récursion.

PYTHON pour les DÉBUTANTS #9#

Les fonctions avancées en Python#

Maintenant que vous maîtrisez les bases des fonctions, découvrons les concepts avancés qui vous permettront d’écrire du code plus élégant et réutilisable.

Paramètres par défaut#

Explication

Les paramètres par défaut permettent de rendre certains arguments optionnels en leur donnant une valeur par défaut qui sera utilisée si l’appelant ne fournit pas de valeur.

Syntaxe de base#

Paramètres avec valeurs par défaut
def saluer(nom, message="Bonjour"):
return f"{message}, {nom}!"
# Utilisation avec paramètre par défaut
print(saluer("Alice")) # "Bonjour, Alice!"
# Utilisation avec paramètre personnalisé
print(saluer("Bob", "Salut")) # "Salut, Bob!"

Paramètres par défaut multiples#

Fonction avec plusieurs paramètres par défaut
def creer_profil(nom, age=25, ville="Paris", actif=True):
return {
"nom": nom,
"age": age,
"ville": ville,
"actif": actif
}
# Utilisation avec différents paramètres
profil1 = creer_profil("Alice")
profil2 = creer_profil("Bob", 30)
profil3 = creer_profil("Charlie", ville="Lyon")
Attention

Les paramètres avec valeurs par défaut doivent toujours être placés après les paramètres obligatoires dans la signature de la fonction.

Arguments nommés et positionnels#

Python permet de passer les arguments par position ou par nom.

Arguments positionnels#

Arguments positionnels
def calculer_prix(prix_base, tva=0.2, remise=0):
prix_final = prix_base * (1 + tva) * (1 - remise)
return prix_final
# Arguments par position
prix1 = calculer_prix(100, 0.1, 0.05)

Arguments nommés#

Arguments nommés (plus lisible)
# Arguments par nom (plus lisible)
prix2 = calculer_prix(
prix_base=100,
remise=0.1,
tva=0.2
)
Conseil

Les arguments nommés rendent votre code plus lisible et permettent de passer les arguments dans n’importe quel ordre. Ils sont particulièrement utiles pour les fonctions avec de nombreux paramètres.

Fonctions avec un nombre variable d’arguments#

*args (arguments positionnels variables)#

Utilisation de *args
def additionner(*nombres):
total = 0
for nombre in nombres:
total += nombre
return total
# Utilisation
resultat1 = additionner(1, 2, 3) # 6
resultat2 = additionner(1, 2, 3, 4, 5) # 15
Définition

*args permet de passer un nombre variable d’arguments positionnels à une fonction. Les arguments sont rassemblés dans un tuple accessible via le nom args.

**kwargs (arguments nommés variables)#

Utilisation de **kwargs
def creer_configuration(**options):
config = {
"debug": False,
"timeout": 30,
"retry": 3
}
config.update(options)
return config
# Utilisation
config1 = creer_configuration(debug=True)
config2 = creer_configuration(timeout=60, retry=5)

Combinaison *args et **kwargs#

Combinaison *args et **kwargs
def fonction_complete(*args, **kwargs):
print("Arguments positionnels:", args)
print("Arguments nommés:", kwargs)
fonction_complete(1, 2, 3, nom="Alice", age=25)

Fonctions lambda (fonctions anonymes)#

Définition

Les fonctions lambda permettent de créer des fonctions simples en une ligne. Elles sont particulièrement utiles pour des opérations courtes utilisées comme arguments d’autres fonctions.

Syntaxe de base#

Fonction lambda vs fonction normale
# Fonction normale
def carre(x):
return x ** 2
# Fonction lambda équivalente
carre_lambda = lambda x: x ** 2
print(carre(5)) # 25
print(carre_lambda(5)) # 25

Utilisation avec les fonctions intégrées#

```python title=“Lambda avec map(), filter() et sorted()” showLineNumbers nombres = [1, 2, 3, 4, 5]

Utilisation avec map()#

carres = list(map(lambda x: x ** 2, nombres)) print(carres) # [1, 4, 9, 16, 25]

Utilisation avec filter()#

pairs = list(filter(lambda x: x % 2 == 0, nombres)) print(pairs) # [2, 4]

Utilisation avec sorted()#

noms = [“Alice”, “Bob”, “Charlie”] noms_tries = sorted(noms, key=lambda nom: len(nom)) print(noms_tries) # [“Bob”, “Alice”, “Charlie”]

<Callout variant="tip">
Les fonctions lambda sont idéales pour des opérations simples. Pour des logiques plus complexes, préférez les fonctions normales avec `python:def` qui sont plus lisibles et peuvent contenir plusieurs instructions.
</Callout>
## Fonctions comme objets de première classe
En Python, les fonctions sont des objets comme les autres.
### Assignation de fonctions
```python title="Assignation et manipulation de fonctions" showLineNumbers
def dire_bonjour():
return "Bonjour!"
def dire_aurevoir():
return "Au revoir!"
# Assignation de fonction
salutation = dire_bonjour
print(salutation()) # "Bonjour!"
salutation = dire_aurevoir
print(salutation()) # "Au revoir!"

Fonctions comme paramètres#

Fonctions en tant que paramètres
def appliquer_operation(nombres, operation):
resultats = []
for nombre in nombres:
resultats.append(operation(nombre))
return resultats
def doubler(x):
return x * 2
def tripler(x):
return x * 3
nombres = [1, 2, 3, 4, 5]
# Utilisation
doubles = appliquer_operation(nombres, doubler)
triples = appliquer_operation(nombres, tripler)
print(doubles) # [2, 4, 6, 8, 10]
print(triples) # [3, 6, 9, 12, 15]

Fonctions imbriquées et closures#

Fonctions imbriquées#

Fonctions imbriquées
def calculatrice():
def addition(a, b):
return a + b
def soustraction(a, b):
return a - b
def multiplication(a, b):
return a * b
return {
"add": addition,
"sub": soustraction,
"mul": multiplication
}
# Utilisation
calc = calculatrice()
resultat = calc["add"](5, 3) # 8

Closures (fermetures)#

Explication

Une closure est une fonction qui “capture” des variables de sa portée environnante. Elle peut accéder et modifier ces variables même après que la fonction externe ait terminé son exécution.

Closures - Fonctions usine
def creer_multiplicateur(facteur):
def multiplier(nombre):
return nombre * facteur
return multiplier
# Création de fonctions spécialisées
multiplier_par_2 = creer_multiplicateur(2)
multiplier_par_3 = creer_multiplicateur(3)
print(multiplier_par_2(5)) # 10
print(multiplier_par_3(5)) # 15

Décorateurs (introduction)#

Définition

Les décorateurs permettent de modifier le comportement des fonctions sans changer leur code source. Ils “enveloppent” une fonction pour ajouter des fonctionnalités supplémentaires.

Décorateur simple#

Décorateur de chronométrage
def chronometrer(fonction):
def wrapper(*args, **kwargs):
import time
debut = time.time()
resultat = fonction(*args, **kwargs)
fin = time.time()
print(f"Temps d'exécution: {fin - debut:.2f} secondes")
return resultat
return wrapper
@chronometrer
def calcul_long():
total = 0
for i in range(1000000):
total += i
return total
resultat = calcul_long()

Récursion#

Explication

La récursion permet à une fonction de s’appeler elle-même. C’est une technique puissante pour résoudre des problèmes qui peuvent être décomposés en sous-problèmes similaires.

Exemple classique : factorielle#

Fonction factorielle récursive
def factorielle(n):
if n <= 1:
return 1
else:
return n * factorielle(n - 1)
print(factorielle(5)) # 120

Exemple : suite de Fibonacci#

Suite de Fibonacci récursive
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10)) # 55
Attention

La récursion peut être inefficace pour certains problèmes comme Fibonacci, car elle recalcule les mêmes valeurs plusieurs fois. Utilisez la mémorisation ou l’itération pour améliorer les performances.

Récursion avec mémorisation#

Fibonacci avec mémorisation
def fibonacci_memo(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
return n
memo[n] = fibonacci_memo(n - 1, memo) + fibonacci_memo(n - 2, memo)
return memo[n]
print(fibonacci_memo(50)) # Beaucoup plus rapide !

Bonnes pratiques#

Documentation des fonctions#

Docstring - Documentation de fonction
def calculer_moyenne(nombres):
"""
Calcule la moyenne d'une liste de nombres.
Args:
nombres (list): Liste de nombres à moyenner
Returns:
float: La moyenne des nombres
Raises:
ValueError: Si la liste est vide
"""
if not nombres:
raise ValueError("La liste ne peut pas être vide")
return sum(nombres) / len(nombres)
Conseil

Utilisez des docstrings pour documenter vos fonctions. Elles aident les autres développeurs (et vous-même plus tard) à comprendre ce que fait votre fonction, quels paramètres elle accepte, et ce qu’elle retourne.

Gestion des erreurs#

Gestion des erreurs dans les fonctions
def diviser(a, b):
try:
return a / b
except ZeroDivisionError:
print("Erreur: Division par zéro")
return None
except TypeError:
print("Erreur: Types invalides")
return None

Exercices pratiques#

Conseil
  1. Calculatrice avancée : Créez une calculatrice avec des opérations personnalisées.

  2. Filtre de données : Utilisez des fonctions lambda pour filtrer des listes de données.

  3. Décorateur de logging : Créez un décorateur qui enregistre les appels de fonction.

  4. Fonction récursive : Implémentez une fonction pour parcourir un arbre de répertoires.

Conclusion#

Les fonctions avancées en Python offrent une grande flexibilité :

  • Paramètres par défaut : Pour des fonctions plus pratiques
  • Arguments variables (*args, **kwargs) : Pour une adaptabilité maximale
  • Fonctions lambda : Pour des opérations simples et élégantes
  • Closures : Pour créer des fonctions spécialisées
  • Récursion : Pour résoudre des problèmes complexes

Maîtrisez ces concepts et vous écrirez du code Python plus professionnel et maintenable !