Rédigé et vérifié par un professeur diplômé de l’École Polytechnique. Découvrir le professeur

En prépa, Python n’est plus un jouet : il sert à calculer des termes de suites, à manipuler des tableaux NumPy et à approcher des solutions numériques. Or les mêmes bugs reviennent à chaque colle et à chaque DS. Voici les 10 erreurs classiques que je vois le plus souvent chez mes élèves, avec pour chacune un extrait fautif, la correction, et le réflexe à garder.


1. Confondre / et // dans une division

Entre deux entiers Python, l’opérateur / renvoie un flottant. Pour un indice entier obtenu par division, on utilise souvent //, qui arrondit vers moins l’infini : 7 // 2 vaut 3, mais -7 // 2 vaut -4. Avec un opérande flottant, // peut lui aussi produire un flottant.

n = 7
milieu = n / 2      # 3.5 (float), pas 3
tab[milieu]         # TypeError : indice non entier

Correction : utilise la division entière // quand tu veux un indice ou un quotient euclidien.

milieu = n // 2     # 3 (int)
tab[milieu]         # OK

Le réflexe : un indice doit être entier. Pour partager une longueur entière n en deux, \(\lfloor n/2\rfloor\) correspond à n // 2. Choisis l’opération selon le problème : tronquer ou arrondir une autre quantité n’est pas toujours la bonne façon de construire un indice.


2. Mélanger str et int sans conversion

La fonction input() renvoie toujours une chaîne de caractères. Additionner cette chaîne à un nombre déclenche une TypeError.

n = input("Entier n : ")
print(n + 1)        # TypeError : can only concatenate str (not "int") to str

Correction : convertis explicitement avec int() ou float().

n = int(input("Entier n : "))
print(n + 1)        # OK

Le piège inverse existe aussi : "3" * 2 donne "33" (répétition de chaîne) et non 6. Dès qu’une opération mélange les types, Python ne devine rien pour toi. Prends l’habitude de convertir la donnée au moment où tu la reçois, pas trois lignes plus loin.


3. Dépasser la borne d’une liste (IndexError)

Une liste de longueur \(n\) a ses éléments indexés de \(0\) à \(n-1\). Vouloir lire l’indice \(n\) provoque une IndexError.

u = [1, 2, 3]       # indices 0, 1, 2
print(u[3])         # IndexError : list index out of range

C’est l’erreur reine sur les suites récurrentes, quand on écrit une formule du type \(u_{n+1} = f(u_n)\) en accédant à u[n+1] alors que la liste n’a pas encore cette case.

u = [1]
for n in range(5):
    u.append(2 * u[n])   # on lit u[n], on ajoute u[n+1] : OK

Le réflexe : le dernier indice valide est len(u) - 1. En cas de doute, affiche len(u) juste avant l’accès litigieux.


4. Confondre l’indice et la valeur

Dans for x in u, x prend les valeurs de la liste. Le réutiliser comme indice peut provoquer une IndexError, comme ci-dessous, ou donner un résultat faux sans erreur si la valeur est un indice valide.

u = [10, 20, 30]
for x in u:
    print(u[x])     # u[10] : IndexError, car x vaut déjà 10 !

Trois possibilités selon ton besoin :

  • Tu veux les valeurs → for x in u: print(x)
  • Tu veux les indices → for i in range(len(u)): print(u[i])
  • Tu veux les deux → for i, x in enumerate(u): print(i, x)

C’est l’erreur la plus fréquente en début d’année : demande-toi toujours « ma variable de boucle, c’est un indice ou une valeur ? » avant d’écrire la ligne suivante.


5. Se tromper d’une unité sur range()

range(n) parcourt \(0, 1, \dots, n-1\) : il s’arrête avant n. Oublier ce détail décale toutes les sommes et tous les produits d’un cran.

# Somme des entiers de 1 à n
S = 0
for k in range(n):     # k va de 0 à n-1 : il manque n !
    S += k

Correction : ajuste les bornes avec range(1, n+1).

S = 0
for k in range(1, n + 1):   # k va de 1 à n
    S += k

Tu peux vérifier la formule attendue \(\displaystyle\sum_{k=1}^{n} k = \displaystyle\frac{n(n+1)}{2}\) sur un petit cas (n = 4 donne 10). Ce contrôle par valeur connue démasque instantanément un décalage d’indice.


6. Boucle infinie et confusion = / == dans un while

Dans une condition, on compare avec ==. Le simple = est une affectation et provoque une SyntaxError dans un while.

while x = 0:        # SyntaxError
    ...

Plus vicieux : la boucle infinie, quand la variable testée n’est jamais mise à jour. Cas typique, la recherche d’un seuil sur une suite qui converge :

u = 1.0
n = 0
while u > 1e-6:
    u = u / 2       # sans cette mise à jour, boucle infinie
    n += 1
print(n)

Le réflexe : vérifie la progression de la boucle et sa condition d’arrêt. Dans cet exemple, les divisions par 2 font tendre la suite vers zéro : elle finit donc par passer sous le seuil positif. Une limite nulle est une justification possible, pas une obligation pour toutes les boucles while.


7. NumPy : copie par référence involontaire

Affecter B = A ne crée pas un nouveau tableau : B et A désignent la même zone mémoire. Modifier l’un modifie l’autre.

import numpy as np
A = np.array([1, 2, 3])
B = A
B[0] = 99
print(A)            # [99  2  3] : A a changé !

Correction : demande une vraie copie avec .copy().

A = np.array([1, 2, 3])  # réinitialiser après le premier exemple
B = A.copy()
B[0] = 99
print(A)                # [1 2 3] : A est resté intact

Même piège avec le slicing : A[1:] renvoie une vue, pas une copie. Dès que tu veux travailler sur un tableau sans abîmer l’original (par exemple sauvegarder un état de suite), pense .copy(). C’est une source d’erreurs fréquente sur les algorithmes qui itèrent sur des matrices.


8. NumPy : erreur de shape et produit matriciel

Deux confusions classiques. D’abord, * fait un produit terme à terme, pas un produit matriciel : pour ce dernier, utilise @ (ou np.dot).

A = np.array([[1, 2], [3, 4]])
B = np.array([[1, 0], [0, 1]])
A * B               # produit terme à terme
A @ B               # vrai produit matriciel

Ensuite, les dimensions doivent être compatibles. Pour multiplier une matrice \((m,n)\) par une matrice \((p,q)\), il faut \(n = p\), sinon :

A = np.zeros((2, 3))
B = np.zeros((2, 2))
A @ B               # ValueError : shapes (2,3) and (2,2) not aligned

Le réflexe : affiche A.shape et B.shape avant tout produit douteux. Et ne mélange pas une liste Python avec un tableau NumPy : convertis d’abord avec np.array(ma_liste).


9. Comparer des flottants avec ==

Les nombres à virgule sont stockés de façon approchée. Résultat, une égalité exacte échoue là où tu l’attends.

Choisis une tolérance adaptée à l’échelle des nombres. math.isclose(a, b, rel_tol=1e-9, abs_tol=1e-12) permet de combiner une tolérance relative et une tolérance absolue utile près de zéro.

print(0.1 + 0.2 == 0.3)     # False !
print(0.1 + 0.2)            # 0.30000000000000004

Correction : compare à une tolérance \(\varepsilon\) au lieu d’une égalité stricte.

a = 0.1 + 0.2
b = 0.3
print(abs(a - b) < 1e-9)    # True

Mathématiquement, on teste \(|a- b| \lt \varepsilon\) avec \(\varepsilon\) petit (souvent \(10^{-9}\)). Ce piège se cumule dans les boucles : en additionnant mille fois 0.001, tu n’obtiens pas exactement 1.0. C’est la même vigilance qu’en calcul manuel, retrouve d’ailleurs les fautes qui coûtent des points dans nos erreurs de calcul en terminale.


10. Portée et paramètre mutable par défaut

Une valeur par défaut mutable (liste, dictionnaire) est créée une seule fois, à la définition de la fonction, puis partagée entre tous les appels. Effet garanti : des résultats qui « se souviennent » des appels précédents.

def ajoute(x, L=[]):
    L.append(x)
    return L

print(ajoute(1))    # [1]
print(ajoute(2))    # [1, 2] : surprise !

Correction : mets None par défaut et crée la liste dans le corps.

def ajoute(x, L=None):
    if L is None:
        L = []
    L.append(x)
    return L

Une affectation simple à un nom dans une fonction crée généralement un nom local. Pour réaffecter un nom global, on utilise global. En revanche, une fonction peut modifier le contenu d’une liste reçue en argument ou accessible globalement sans réaffecter ce nom. Distingue la valeur renvoyée, la réaffectation d’un nom et la modification d’un objet.


Comment progresser au-delà de ces erreurs

La compétence qui te fera vraiment gagner du temps, c’est lire un traceback. Quand Python plante, ne referme pas la fenêtre : lis la dernière ligne (le type d’erreur et le message) puis le fichier et le numéro de ligne indiqués dans le traceback ; certains environnements ajoutent une flèche. Le tableau ci-dessous rassemble six exceptions fréquentes ; une erreur de logique peut aussi ne déclencher aucune exception.

Références : erreurs et exceptions Python, copies et vues NumPy.

ExceptionCause fréquenteRemède
SyntaxErrorOubli de deux-points ou de parenthèseVérifier la ligne indiquée et celle du dessus
IndexErrorIndice hors limites d’une liste ou d’un tableauContrôler len et les bornes de range
TypeErrorOpération entre types incompatiblesConvertir avec int, float ou str
NameErrorVariable non définie ou faute de frappeVérifier l’orthographe et l’ordre des lignes
ValueErrorConversion impossible, par exemple int sur du texteValider la donnée avant conversion
ZeroDivisionErrorDivision par une quantité nulleTester le dénominateur avant de diviser

Concrètement, dès aujourd’hui : reprends ton dernier TP, provoque volontairement chacune de ces erreurs et entraîne-toi à les corriger en moins d’une minute. Teste aussi systématiquement tes fonctions sur les cas limites (liste vide, \(n = 0\), premier terme d’une suite).

Pour élargir, ces bugs de code sont cousins des maladresses de raisonnement : consulte nos erreurs typiques en prépa scientifique et nos erreurs de rédaction en DS. Et si tu hésites encore sur la filière, notre page la prépa scientifique est-elle faite pour toi répond aux questions clés.


Questions fréquentes

Quelle est la différence entre la barre oblique simple et double en Python ?

Pour deux entiers, 7 / 2 donne le flottant 3.5, tandis que 7 // 2 donne l’entier 3. La division // arrondit vers moins l’infini. Vérifie aussi les types : 7.0 // 2 renvoie 3.0, inutilisable tel quel comme indice de liste.

Pourquoi 0.1 plus 0.2 ne vaut pas 0.3 en Python ?

Les flottants sont stockés de manière approchée, donc 0.1 + 0.2 donne 0.30000000000000004. Ne compare jamais deux flottants avec l’égalité stricte. Teste plutôt abs(a – b) inférieur à une petite tolérance, par exemple 1e-9.

Comment éviter une IndexError sur une liste ?

Rappelle-toi qu’une liste de longueur n a ses indices de 0 à n moins 1. Le dernier indice valide est donc len(liste) moins 1. En cas de doute, affiche len(liste) juste avant l’accès et vérifie les bornes de tes range.

Pourquoi ma copie de tableau NumPy modifie l’original ?

Parce que B égale A ne crée pas un nouveau tableau : les deux noms pointent vers la même mémoire. Pour obtenir une vraie copie indépendante, utilise A.copy(). Attention, le slicing renvoie aussi une vue, pas une copie.

Comment lire rapidement un message d’erreur Python ?

Lis la dernière ligne pour connaître le type d’exception et son message, puis retrouve le fichier, le numéro de ligne et le contexte indiqués dans le traceback. Une flèche peut aider selon l’environnement. Vérifie ensuite les valeurs et les types impliqués.

Logo-excellence-maths
Progresser en maths avec un professeur de Polytechnique
Un accompagnement individuel pour transformer tes résultats et atteindre tes objectifs.