Mode Découverte Gratuit (Accès 1-Clic)

Vous profitez d'un accès libre aux premières leçons de ce cours. Créez un compte gratuit pour enregistrer votre progression et accéder aux quiz !

Créer un compte gratuit

Structures de Contrôle : Efficacité et Clarté

Structures de Contrôle : Efficacité et Clarté

Bienvenue dans cette leçon dédiée à l'optimisation de vos structures de contrôle en Python. En tant que débutant, vous avez appris à utiliser les boucles for et while, ainsi que les conditions if, elif, et else. Aujourd'hui, nous allons aller un cran plus loin en explorant comment rendre ces outils non seulement fonctionnels, mais aussi *efficaces

  • et clairs.

Pourquoi est-ce important ? Un code efficace s'exécute plus rapidement et consomme moins de ressources. Un code clair est plus facile à lire, à comprendre et à maintenir, que ce soit par vous-même dans le futur, ou par d'autres développeurs. C'est la marque d'un bon programmeur de savoir écrire du code qui est à la fois performant et élégant.

1. Optimisation des Conditions (if/elif/else)

Les blocs conditionnels sont omniprésents. Leur bonne utilisation peut grandement améliorer la lisibilité et parfois la performance de votre code.

1.1 Ordre des Conditions

Placez les conditions les plus probables ou les moins coûteuses à vérifier en premier. Cela permet à Python de sortir du bloc if/elif/else plus rapidement si la première condition est remplie, évitant ainsi d'évaluer les conditions suivantes.

Exemple Conceptuel :
Si vous vérifiez l'âge d'un utilisateur, et que la majorité des utilisateurs sont mineurs (disons 70%), vérifiez d'abord cette condition.

Plutôt que :

if age >= 18:
print("Adulte")
elif age < 18:
print("Mineur")

Écrivez plutôt :

if age < 18:
print("Mineur")
elif age >= 18:
print("Adulte")

Bien que cet exemple soit simple et que les deux conditions soient mutuellement exclusives (donc le elif ne sera jamais atteint si le if est vrai), l'idée est de prioriser les conditions qui ont la plus forte probabilité d'être vraies ou celles qui sont les plus rapides à évaluer.

1.2 Éviter les Conditions Redondantes et Inutiles

N'incluez pas de vérifications qui sont implicitement traitées par des conditions précédentes. Par exemple, si vous avez if x > 10: ... elif x > 5: ..., le second x > 5 ne sera évalué que si x n'est PAS > 10, ce qui signifie implicitement que x est entre 5 et 10. Pas besoin de vérifier x <= 10 spécifiquement dans le elif.

1.3 Utilisation des Opérateurs Logiques (and, or, not)

Pour des conditions multiples, les opérateurs logiques sont vos amis. Ils permettent de combiner des expressions booléennes de manière concise.

  • and : Les deux conditions doivent être vraies.
  • or : Au moins une des conditions doit être vraie.
  • not : Inverse la valeur de vérité d'une condition.

Exemple :
Plutôt que :

if age >= 18:
if a_un_permis == True:
print("Peut conduire")

Utilisez :

if age >= 18 and a_un_permis:
print("Peut conduire")

C'est plus lisible et plus compact.

1.4 L'Expression Conditionnelle (Opérateur Ternaire)

Pour des assignations simples basées sur une condition, Python offre une syntaxe concise appelée "opérateur ternaire".

Syntaxe : valeur_si_vraie if condition else valeur_si_fausse

Exemple :
Plutôt que :

if x > 0:
signe = "positif"
else:
signe = "négatif ou nul"

Utilisez :

signe = "positif" if x > 0 else "négatif ou nul"

Cela condense trois lignes en une seule, améliorant la clarté pour des cas simples.

2. Optimisation des Boucles (for/while)

Les boucles sont souvent les parties de votre code où la performance peut être la plus critique, car les opérations à l'intérieur sont répétées de nombreuses fois.

2.1 Choisir la Bonne Boucle

  • *for

  • : Idéale pour itérer sur une séquence (liste, tuple, chaîne, dictionnaire, range) un nombre défini de fois, ou pour chaque élément d'un itérable.

  • *while

  • : Idéale lorsque le nombre d'itérations est inconnu à l'avance et dépend d'une condition qui doit rester vraie.

En général, préférez for lorsque c'est possible car c'est souvent plus idiomatique et plus simple à lire pour les itérations sur des collections.

2.2 Utiliser enumerate pour les Indices

Si vous avez besoin à la fois de l'élément et de son indice lors de l'itération sur une liste, n'utilisez pas range(len(liste)). Utilisez plutôt enumerate.

Plutôt que :

for i in range(len(ma_liste)):
print(f"Élément à l'indice {i} : {ma_liste[i]}")

Utilisez :

for i, element in enumerate(ma_liste):
print(f"Élément à l'indice {i} : {element}")

C'est plus Pythonique, plus lisible et parfois plus performant car enumerate génère les paires (indice, élément) au fur et à mesure, sans créer une liste d'indices intermédiaire.

2.3 Utiliser zip pour Itérer sur Plusieurs Listes

Quand vous devez itérer sur plusieurs listes en parallèle, zip est l'outil parfait.

Exemple :

noms = ["Alice", "Bob"]
ages = [25, 30]

for nom, age in zip(noms, ages):
print(f"{nom} a {age} ans.")

C'est beaucoup plus propre que de gérer des indices manuellement et d'accéder à noms[i] et ages[i].

2.4 Minimiser les Opérations Coûteuses à l'Intérieur de la Boucle

Toute opération effectuée à l'intérieur d'une boucle sera répétée autant de fois que la boucle s'exécute. Si une opération peut être effectuée une seule fois avant la boucle, faites-le.

Exemple :
Si vous avez besoin de la longueur d'une liste n fois dans une boucle, calculez-la une fois :

Plutôt que :

ma_liste = [1, 2, 3, 4, 5]
for _ in range(100):
longueur = len(ma_liste)

Cette opération est répétée 100 fois inutilement

... utiliser longueur

Utilisez :

ma_liste = [1, 2, 3, 4, 5]
longueur = len(ma_liste)

Calculé une seule fois

for _ in range(100):

... utiliser longueur

De même, si vous avez un calcul complexe qui donne toujours le même résultat et n'utilise pas les variables de la boucle, sortez-le de la boucle.

2.5 break et continue : À Utiliser avec Parcimonie

  • break : Termine la boucle immédiatement.
  • continue : Passe à l'itération suivante de la boucle.

Ces mots-clés peuvent être utiles pour sortir prématurément d'une boucle ou pour ignorer certaines itérations. Cependant, une utilisation excessive peut rendre le flux de contrôle difficile à suivre. Préférez structurer vos conditions de manière à ce que break et continue ne soient nécessaires que pour des cas exceptionnels et clairement justifiés.

3. Compréhensions de Liste (List Comprehensions)

Les compréhensions de liste sont l'une des fonctionnalités les plus puissantes et idiomatiques de Python pour créer des listes. Elles offrent une manière concise et souvent plus performante de construire de nouvelles listes à partir d'itérables existants.

3.1 Qu'est-ce qu'une Compréhension de Liste ?

C'est une syntaxe compacte pour créer une nouvelle liste en appliquant une expression à chaque élément d'un itérable, éventuellement filtré par une condition.

Syntaxe de base :
nouvelle_liste = [expression for element in iterable]

C'est équivalent à :

nouvelle_liste = []
for element in iterable:
nouvelle_liste.append(expression)

3.2 Avantages

  • *Concision

  • : Réduit plusieurs lignes de code en une seule.

  • *Lisibilité

  • : Pour des cas simples, la syntaxe est souvent plus intuitive.

  • *Performance

  • : Les compréhensions de liste sont généralement plus rapides que les boucles for explicites avec append(), car elles sont optimisées au niveau du CPython.

3.3 Exemple Simple : Transformer chaque élément

Prenez une liste de nombres et créez une nouvelle liste avec les carrés de ces nombres.

Avec une boucle for traditionnelle :

nombres = [1, 2, 3, 4, 5]
carrés = []
for n in nombres:
carrés.append(n

  • n)
    print(carrés)

Output: [1, 4, 9, 16, 25]

Avec une compréhension de liste :

nombres = [1, 2, 3, 4, 5]
carrés = [n

  • n for n in nombres]
    print(carrés)

Output: [1, 4, 9, 16, 25]

3.4 Compréhensions de Liste avec Conditions

Vous pouvez ajouter une condition pour filtrer les éléments de l'itérable original.

Syntaxe :
nouvelle_liste = [expression for element in iterable if condition]

*Exemple :

  • Filtrer les nombres pairs et les mettre au carré.

nombres = [1, 2, 3, 4, 5, 6]
carrés_pairs = [n

  • n for n in nombres if n % 2 == 0]
    print(carrés_pairs)

Output: [4, 16, 36]

Ceci est équivalent à :

nombres = [1, 2, 3, 4, 5, 6]
carrés_pairs = []
for n in nombres:
if n % 2 == 0:
carrés_pairs.append(n

  • n)

3.5 Compréhensions de Liste avec Condition if/else dans l'Expression

Si vous voulez appliquer une expression différente selon une condition, et toujours inclure l'élément (potentiellement transformé) dans la nouvelle liste, la condition if/else se place avant le for.

Syntaxe :
nouvelle_liste = [expression_si_vrai if condition else expression_si_faux for element in iterable]

*Exemple :

  • Mettre au carré les nombres pairs, laisser les nombres impairs tels quels.

nombres = [1, 2, 3, 4, 5, 6]
resultat = [n

  • n if n % 2 == 0 else n for n in nombres]
    print(resultat)

Output: [1, 4, 3, 16, 5, 36]

Ceci est équivalent à :

nombres = [1, 2, 3, 4, 5, 6]
resultat = []
for n in nombres:
if n % 2 == 0:
resultat.append(n

  • n)
    else:
    resultat.append(n)

3.6 Autres Types de Compréhensions (pour information)

Bien que cette leçon se concentre sur les compréhensions de liste, sachez qu'il existe aussi :

  • *Compréhensions d'ensemble (Set Comprehensions)

  • : Utilisent des accolades {} et créent des ensembles (éléments uniques).
    mon_ensemble = {x*x for x in [1,1,2,3]} donnera {1, 4, 9}.

  • *Compréhensions de dictionnaire (Dictionary Comprehensions)

  • : Utilisent des accolades {} et key: value.
    mon_dict = {x: x*x for x in range(3)} donnera {0: 0, 1: 1, 2: 4}.

  • *Expressions génératrices (Generator Expressions)

  • : Utilisent des parenthèses () et créent un itérateur qui produit des valeurs à la demande, très efficace pour de grandes séquences.
    mon_generateur = (x*x for x in range(1000000)).

4. Principes Généraux de Code Propre et Efficace

Au-delà des optimisations spécifiques aux structures de contrôle, gardez ces principes à l'esprit :

  • *Lisibilité avant la Micro-Optimisation

  • : Sauf si vous avez une contrainte de performance critique (mesurée avec un profileur), privilégiez toujours le code le plus clair et le plus facile à comprendre. Un code légèrement moins performant mais lisible est souvent préférable à un code obscur et à peine plus rapide.

  • *Le Zen de Python

  • : Tapez import this dans votre interpréteur Python. Vous y trouverez 19 aphorismes sur la philosophie de Python, dont "Beautiful is better than ugly." et "Readability counts.".

  • *Nommage Significatif

  • : Utilisez des noms de variables, de fonctions et de classes qui décrivent clairement leur rôle. x et y sont acceptables pour des coordonnées, mais nombre_utilisateur est bien mieux que n pour un nombre d'utilisateurs.

  • *Commentaires et Docstrings

  • : Expliquez les parties complexes de votre code, le but des fonctions ou des classes. Un bon code est souvent auto-documenté, mais quelques commentaires judicieux peuvent faire une grande différence.

  • **Éviter la duplication de code (DRY

  • Don't Repeat Yourself)*

  • : Si vous vous retrouvez à écrire le même bloc de code plusieurs fois, c'est probablement le signe qu'il devrait être encapsulé dans une fonction.

En appliquant ces principes et les techniques d'optimisation des structures de contrôle, vous écrirez du code Python non seulement fonctionnel, mais aussi professionnel, efficace et agréable à lire. La maîtrise de ces techniques est un pas important vers la maîtrise de Python.

Voici quelques concepts mathématiques simples pour illustrer la complexité, bien que nous soyons pour débutants, il est bon de comprendre que les boucles ont un "coût".

La complexité temporelle d'un algorithme est souvent exprimée avec la notation Grand O ( \(O(n)\) ).

  • Une opération simple (assignation, addition) est généralement \(O(1)\) . Sa durée est constante.
  • Une boucle simple sur une liste de n éléments (par exemple, calculer la somme) est généralement \(O(n)\) . Sa durée est proportionnelle au nombre d'éléments.
    \(T_{boucle} \approx k \times n\)
    où \(k\) est le coût d'une itération.
  • Des boucles imbriquées (par exemple, pour trouver des paires dans une liste) peuvent être \(O(n^2)\) .
    \(T_{boucles\_imbriquees} \approx k \times n^2\)

Les compréhensions de liste sont souvent plus proches d'un \(O(n)\) optimisé, en comparaison d'une boucle for avec append qui pourrait avoir de légers surcoûts d'opérations Python interprétées.

Comprendre que le nombre d'opérations croît avec la taille de vos données (n) est crucial pour écrire du code efficace. L'objectif n'est pas toujours de passer de \(O(n^2)\) à \(O(n)\) , ce qui est une optimisation majeure, mais parfois simplement de réduire le coefficient \(k\) de l'équation en minimisant les opérations inutiles dans la boucle.

© 2026 DzSmartEduc Learning Platform

تواصل معنا على واتساب 17h00 - 22h00 • 7j/7