Aller au contenu

Cours#

Les bases de la programmation Python

Programme (BO) « Mettre en évidence un corpus de constructions élémentaires. » Ces constructions sont : « séquences, affectation, conditionnelles, boucles bornées, boucles non bornées, appels de fonction ». On y ajoute la spécification d’une fonction (prototype, préconditions, postconditions) et l’usage de jeux de tests.
Prérequis aucun. Il suffit de savoir ouvrir une console ou un éditeur Python en ligne.
Objectifs lire, écrire et exécuter un programme simple ; maîtriser les six constructions élémentaires ; spécifier et tester une fonction. C’est le socle de toute l’année (et de toute la suite).

Situation de départ

  1. Comment faire échanger leurs contenus à deux « boîtes » d’un programme sans perdre aucune des deux valeurs ?

  2. Comment faire calculer \(1 + 2 + \dots + 100\) à un ordinateur sans écrire soi-même les cent nombres ?

  3. Un programme qui répète une action peut-il ne jamais s’arrêter ? Comment être sûr qu’il s’arrêtera ?

Programmer, c’est quoi ?#

Un programme est une suite d’instructions, écrites dans un langage de programmation, qu’un ordinateur exécute pour accomplir une tâche. L’idée est plus ancienne que les ordinateurs eux-mêmes : dès 1843, la mathématicienne Ada Lovelace rédige ce que l’on considère comme le premier programme de l’histoire, destiné à une machine qui ne sera jamais construite. Le mot algorithme, lui, vient du nom du savant persan al-Khwârizmî (IXe siècle).

Pour les curieux (facultatif) — Un peu d’histoire

Ada Lovelace (1815–1852), fille du poète Byron, se passionne pour la machine analytique imaginée par l’Anglais Charles Babbage : une calculatrice mécanique programmable par cartes perforées. En 1843, elle traduit un article sur cette machine et l’enrichit de notes trois fois plus longues que le texte. La dernière, la note G, détaille pas à pas comment la machine calculerait les nombres de Bernoulli, avec des opérations répétées : c’est le premier programme publié. Mille ans plus tôt, vers 820, al-Khwârizmî, savant de la « Maison de la sagesse » de Bagdad, écrit un traité de calcul dont le titre a donné le mot algèbre (al-jabr), et un autre sur les chiffres indiens dont la traduction latine, Algoritmi de numero Indorum, a donné le mot algorithme.


Ada Lovelace (portrait par A. E. Chalon, v. 1840)


Le tableau de la note G (1843)


L’Algèbre d’al-Khwârizmî (copie de 1342, Oxford)

Définition 1 — Algorithme et programme

Un algorithme est une méthode : une suite finie et non ambiguë d’étapes qui, à partir de données, produit un résultat. Un programme est la traduction d’un algorithme dans un langage que la machine peut exécuter.

Nous utiliserons le langage Python, créé en 1991 par le Néerlandais Guido van Rossum. Il est aujourd’hui l’un des langages les plus enseignés et les plus utilisés au monde, pour sa lisibilité.

Pour les curieux (facultatif) — Pourquoi « Python » ?

Rien à voir avec le serpent ! Guido van Rossum était fan de la troupe comique britannique Monty Python. C’est pourquoi la documentation officielle fourmille encore de références à leurs sketchs (et de spam, eggs et autres ham en guise d’exemples).

La première construction : la séquence#

Quand on écrit plusieurs instructions les unes sous les autres, Python les exécute dans l’ordre, de haut en bas, une à la fois. C’est la construction la plus simple : la séquence.

Exemple — Testez ce programme dans une console ou un éditeur en ligne

print("Bonjour")
print("et")
print("au revoir")
Correction

Les trois lignes s’affichent dans l’ordre où elles sont écrites :

Bonjour
et
au revoir

Règle 1 — L’ordre compte

Dans une séquence, l’ordre des instructions détermine le résultat. Échanger deux lignes peut tout changer : la machine ne « devine » pas votre intention, elle applique vos instructions à la lettre.

Remarque

print(...) est un appel de fonction : on demande à une fonction déjà écrite (print) d’afficher ce qu’on lui donne entre parenthèses. Nous reviendrons longuement sur les fonctions.

Variables et affectation#

À quoi sert une variable ?#

Un programme manipule des données : un âge, un prix, un nom, une note… Pour les conserver et les réutiliser, on leur donne un nom. Ce nom, associé à une valeur, s’appelle une variable.

age = 15
prix = 12.5
prenom = "Ada"

Définition 2 — Variable

Une variable est un nom qui désigne un emplacement de la mémoire où est rangée une valeur. On peut lire cette valeur (l’utiliser) et l’écrire (la modifier).

L’image classique est celle du casier étiqueté : le nom de la variable est l’étiquette collée sur le casier, la valeur est ce qui se trouve à l’intérieur. On ne s’intéresse jamais à l’adresse exacte du casier dans la mémoire ; l’étiquette suffit.

Trois casiers en mémoire : l’étiquette (le nom) désigne le contenu (la valeur).

Ce modèle du casier est provisoire : il suffit pour tout ce chapitre. Le chapitre Les types construits le précisera : on y verra qu’une variable est plutôt une étiquette attachée à une valeur rangée ailleurs en mémoire.

L’affectation : une histoire en deux temps#

L’instruction age = 15 s’appelle une affectation. Le symbole = ne veut pas dire « égal » au sens mathématique : il veut dire « prend pour valeur », ou « reçoit ». On lit age = 15 comme « age reçoit 15 ».

Règle 2 — Le mécanisme de l’affectation

Une affectation nom = expression se déroule toujours en deux temps :

  1. Python évalue d’abord la partie droite (il calcule la valeur de l’expression) ;

  2. puis il range cette valeur dans la variable nommée à gauche.

On lit et on calcule à droite, on range à gauche.

↺ Retour sur l'activité. Dans le programme 2 de l’activité « L’ordinateur humain », vous avez déjà commencé par la droite : calculer n + 1 avec l’ancienne valeur 5, puis gommer la boîte n pour y écrire 6.

Ce mécanisme éclaire une ligne qui, sinon, semble absurde en mathématiques :

n = 5
n = n + 1

La valeur de n passe donc de 5 à 6. Cette écriture, très fréquente, s’appelle un incrément.

Exemple — Le grand classique : échanger le contenu de deux variables. Prévoyez l’affichage

a = 1
b = 2
a = b
b = a
print(a, b)
Correction

Beaucoup attendent 2 1… mais le programme affiche 2 2 ! À la ligne a = b, a vaut désormais 2 ; la valeur 1 est perdue. La ligne suivante range donc 2 (la valeur actuelle de a) dans b.

Règle 3 — Échanger deux variables

Pour ne pas perdre une valeur, on utilise une variable temporaire :

a = 1
b = 2
temp = a      # on met a l'abri la valeur de a
a = b
b = temp
print(a, b)   # affiche : 2 1

↺ Retour sur l'activité. Le programme 3 de l’activité affichait 2 2 pour cette raison ; la troisième boîte c que vous avez proposée pour le corriger joue exactement le rôle de temp.

Remarque

La variable temporaire est indispensable : sans elle, la première affectation a = b écraserait la valeur de a, alors définitivement perdue. C’est l’image des deux verres, l’un d’eau, l’autre de jus : pour intervertir leurs contenus, il faut un troisième verre vide.

▶ Exercices d'application : exercices 1 et 2 (lire une trace, échanger deux variables)

Les types de données de base#

Chaque valeur a un type, qui décrit sa nature et les opérations permises. En classe de première, quatre types de base suffisent :

Type Nature Exemples
int entier 15, -3, 0
float nombre à virgule (« flottant ») 12.5, -0.1, 3.0
str chaîne de caractères (texte) "Ada", ’bonjour’
bool booléen (vrai/faux) True, False

La fonction type(...) renvoie le type d’une valeur :

type(15)       # <class 'int'>
type(12.5)     # <class 'float'>
type("Ada")    # <class 'str'>
type(3 == 3)   # <class 'bool'>

Sur les nombres, Python dispose des opérations usuelles, et de deux opérations propres à la division entière :

+ - * / // % **
addition soustraction multiplication division quotient entier reste puissance
7 + 2 \(\to\) 9 7 - 2 \(\to\) 5 7 * 2 \(\to\) 14 7 / 2 \(\to\) 3.5 7 // 2 \(\to\) 3 7 % 2 \(\to\) 1 7 ** 2 \(\to\) 49

Pour les curieux (facultatif) — Typage dynamique

Python est à typage dynamique : on ne déclare pas le type d’une variable, il est déduit de la valeur rangée, et il peut changer au fil du programme. Pratique, mais il faut rester vigilant : additionner un int et un str provoque une erreur.

Remarque — Deux pièges célèbres à connaître

  • Les entiers de Python sont de taille arbitraire. Contrairement à beaucoup de langages, Python calcule 2 ** 1000 sans broncher : la seule limite est la mémoire de la machine.

  • Les flottants sont approximatifs. Testez 0.1 + 0.2 : Python répond 0.30000000000000004 ! Un nombre à virgule est stocké en binaire de manière approchée. On n’écrit donc jamais if x == 0.3 sur des flottants ; on teste plutôt si l’écart est très petit.

Lire une entrée au clavier et convertir#

La fonction input(...) affiche un message, attend que l’utilisateur tape quelque chose au clavier puis valide, et renvoie ce qui a été tapé, toujours sous forme de chaîne (str), même si l’on a tapé des chiffres. Pour calculer avec, il faut donc convertir la valeur dans le bon type :

Conversion Rôle Exemple
int(...) vers un entier int("17") \(\to\) 17
float(...) vers un flottant float("12.5") \(\to\) 12.5
str(...) vers une chaîne str(17) \(\to\) "17"
age = int(input("Votre age ? "))   # on tape 16 : age vaut 16
print("Dans un an, vous aurez", age + 1, "ans")

Remarque

Sans int, age vaudrait la chaîne "16", et age + 1 provoquerait une erreur : on ne peut pas additionner un str et un int. De même, int("deux") provoque une erreur : la chaîne doit représenter un nombre.

Premier contact avec les chaînes de caractères#

Une chaîne est une suite de caractères, numérotés à partir de 0. Voici les opérations dont on se sert dès ce chapitre ; le chapitre Les types construits les reprendra en détail.

>>> mot = "radar"
>>> len(mot)            # nombre de caracteres
5
>>> mot[0]              # caractere en position 0 : le premier
'r'
>>> mot[-1]             # le dernier caractere
'r'
>>> "d" in mot          # ce caractere est-il dans la chaine ?
True
>>> "Ada" + " Lovelace" # concatenation : on met bout a bout
'Ada Lovelace'
>>> "*" * 3             # repetition
'***'

Si mot a n caractères, les positions vont de 0 à n - 1 : mot[n] provoque une erreur.

Remarque — Compter depuis la fin : les positions négatives

Python accepte aussi des positions négatives, qui se comptent à partir de la fin : mot[-1] est le dernier caractère, mot[-2] l’avant-dernier, etc. Ainsi mot[-1] est un raccourci pour mot[len(mot) - 1].

caractère r a d a r
position 0 1 2 3 4
position négative -5 -4 -3 -2 -1

Sur un mot vide (""), mot[-1] provoque une erreur, comme mot[0] : il n’y a pas de dernier caractère.

On verra avec la boucle for comment parcourir une chaîne caractère par caractère.

Bien nommer ses variables#

Un programme se lit bien plus souvent qu’il ne s’écrit. Le choix des noms est donc essentiel.

Règle 4 — Règles et conventions de nommage

  • un nom commence par une lettre ou _, puis lettres, chiffres, _ ; pas d’espace, pas d’accent conseillé ;

  • Python distingue les majuscules : note et Note sont deux variables différentes ;

  • par convention, on écrit en minuscules_avec_underscores (style snake_case) ;

  • on choisit des noms parlants : prix_total plutôt que x ou truc ;

  • on ne peut pas utiliser un mot réservé du langage (if, for, while, def, return…).

Écrire une fonction : le gabarit

Dès les premiers exercices, on vous demande d’« écrire une fonction ». Pour l’instant, utilisez-la comme une boîte noire : on lui donne des valeurs (les paramètres), elle renvoie un résultat. Il suffit de recopier ce gabarit ; la section Les fonctions l’approfondira.

def nom_de_la_fonction(parametre1, parametre2):
    resultat = ...      # le calcul, avec les parametres
    return resultat     # la valeur renvoyee
  • la ligne def se termine par un deux-points : ; les lignes suivantes sont décalées de 4 espaces ;

  • return indique la valeur que la fonction renvoie ;

  • certaines fonctions des exercices affichent (avec print) au lieu de renvoyer : on les appelle de la même façon.

Exemple — Le prix d’un achat

Écrire une fonction prix_total(prix, quantite) qui renvoie le prix à payer pour quantite articles à prix euros pièce.

Correction

On suit le gabarit :

def prix_total(prix, quantite):
    total = prix * quantite
    return total

On exécute d’abord le fichier : la définition seule n’affiche rien. Puis on appelle la fonction dans la console, avec des valeurs dont on connaît le résultat, pour la tester :

>>> prix_total(2.5, 4)
10.0
>>> prix_total(3, 0)
0

▶ Exercices d'application : exercices 3 à 5 (// et % ; les fonctions s’écrivent avec le gabarit ci-dessus) et 40, 41 (entraînement : int(input(...)), longueur et indices d’une chaîne)

Les conditionnelles : if, elif, else#

Jusqu’ici, tout s’exécutait ligne après ligne. Or un programme doit souvent choisir entre plusieurs comportements selon les données. C’est le rôle de la construction conditionnelle.

Booléens et conditions#

Une condition est une expression dont la valeur est un booléen : True ou False. On la construit avec des opérateurs de comparaison :

== != < <= > >=
égal différent inférieur inf. ou égal supérieur sup. ou égal

Règle 5 — = n’est pas ==

= affecte une valeur (« reçoit ») ; == teste l’égalité (« est-il égal à ? ») et renvoie un booléen. Les confondre est l’une des erreurs les plus fréquentes du débutant.

On combine plusieurs conditions avec les opérateurs booléens and, or, not :

age = 16
age >= 13 and age <= 17    # True : un adolescent
not (age == 18)            # True

À retenir — Évaluation « paresseuse » de and et or

Les opérateurs and et or sont séquentiels : Python évalue les conditions de gauche à droite et s’arrête dès que le résultat est connu. Dans a and b, si a est déjà False, b n’est même pas évalué (le résultat est forcément False). On exploite cela pour se protéger, par exemple dans n != 0 and total / n > 1.

La syntaxe : le rôle capital de l’indentation#

temperature = 12
if temperature < 0:
    print("Il gele !")
    print("Couvre-toi.")
else:
    print("Pas de gel.")
print("Bonne journee.")     # toujours execute

Deux points de syntaxe sont obligatoires en Python : le deux-points : en fin de ligne if/else, et l’indentation (le décalage vers la droite) des lignes qui dépendent du test.

Règle 6 — L’indentation est la structure

Là où d’autres langages utilisent des accolades, Python utilise le décalage pour délimiter un bloc d’instructions. Toutes les lignes indentées d’un même cran après le : forment le bloc exécuté si la condition est vraie. Une indentation fautive change le sens du programme, ou provoque une IndentationError. Une seule règle d’or : on ne mélange jamais espaces et tabulations (le standard : 4 espaces).

Pour les curieux (facultatif) — Une histoire de goût… devenu règle

Dans la plupart des langages, l’indentation n’est qu’une politesse pour le lecteur humain. Python a fait un choix radical : la rendre obligatoire et signifiante. Résultat, un code Python mal rangé ne s’exécute pas — ce qui force chacun à écrire proprement. Certains détestent, beaucoup adorent.

Les cas multiples : elif#

Pour enchaîner plusieurs tests, on intercale des elif (contraction de else if). Python teste les conditions dans l’ordre et exécute le premier bloc dont la condition est vraie ; les autres sont ignorés.

Exemple — Attribuer une mention à une note sur 20

Écrire une instruction qui range dans mention la mention correspondant à note : « Très bien » à partir de 16, « Bien » à partir de 14, « Assez bien » à partir de 12, « Admis » (sans mention) à partir de 10, « Refusé » en dessous.

Correction

On enchaîne les tests avec elif :

if note >= 16:
    mention = "Tres bien"
elif note >= 14:
    mention = "Bien"
elif note >= 12:
    mention = "Assez bien"
elif note >= 10:
    mention = "Admis"
else:
    mention = "Refuse"

Remarque

L’ordre est crucial : une note de 17 vérifie aussi note >= 14, mais comme note >= 16 est testée d’abord et acceptée, on obtient bien « Très bien ». On va donc du cas le plus exigeant au moins exigeant.

Un test très utile : la divisibilité#

L’opérateur % (le modulo) donne le reste d’une division entière. Un nombre a est divisible par b exactement lorsque a % b vaut 0.

if n % 2 == 0:
    print("n est pair")
else:
    print("n est impair")

▶ Exercices d'application : exercices 6 à 13 (les conditionnelles)

Les boucles bornées : for#

Répéter une action est le cœur de la puissance d’un ordinateur. Quand on connaît à l’avance le nombre de répétitions, on utilise une boucle bornée, la boucle for.

Répéter un nombre connu de fois#

for i in range(5):
    print("Au travail !")

Ce programme affiche cinq fois la même ligne. range(5) produit la suite des entiers 0, 1, 2, 3, 4 (cinq valeurs, à partir de 0, sans atteindre 5), et la variable i prend successivement chacune de ces valeurs.

Remarque — Bientôt avec la tortue

Le complément Dessiner avec la tortue, qui suit ce chapitre, fera voir cette boucle : un carré, c’est for cote in range(4): suivi de « avancer, tourner ». Il permettra de s’entraîner aux boucles en dessinant.

Définition 3 — range

  • range(n) : les entiers de 0 à n-1 ;

  • range(a, b) : les entiers de a à b-1 (la borne b est exclue) ;

  • range(a, b, pas) : de a à b-1 en avançant de pas (le pas peut être négatif).

Exemple — Prévoyez ce que produit chaque boucle, puis vérifiez

for i in range(1, 6):
    print(i)

for i in range(0, 10, 2):
    print(i)

for i in range(10, 0, -1):
    print(i)
Correction

Chaque print affiche un nombre par ligne :

  • la 1re boucle affiche 1 2 3 4 5 (la borne 6 est exclue) ;

  • la 2e affiche 0 2 4 6 8 (on avance de 2, 10 est exclu) ;

  • la 3e affiche 10 9 8 7 6 5 4 3 2 1 : un compte à rebours (pas de -1, 0 est exclu).

Exemple — Parcourir une chaîne

La boucle for peut aussi parcourir directement une chaîne : la variable prend successivement chaque caractère.

for lettre in "Ada":
    print(lettre)
Correction

Le programme affiche A, puis d, puis a, un par ligne. Avec un test if lettre in "aeiouy": dans la boucle, on peut par exemple repérer les voyelles d’un mot.

Pour les curieux (facultatif) — Pourquoi commencer à 0 ?

Ce choix déroute au début, mais il est partout en informatique : les cases d’un tableau seront elles aussi numérotées à partir de 0. Le grand informaticien Edsger Dijkstra a même écrit une note célèbre pour défendre les intervalles « borne de gauche incluse, borne de droite exclue » : ils rendent les calculs de longueurs plus simples (\(b - a\) valeurs).

Le motif de l’accumulateur#

La boucle for sert rarement à répéter à l’identique : le plus souvent, la variable de boucle intervient dans le calcul. Le motif le plus important est l’accumulateur : une variable que l’on met à jour à chaque tour.

Exemple — Calculer la somme des entiers de 1 à 100

Correction

On utilise un accumulateur total :

total = 0                 # on initialise l'accumulateur
for i in range(1, 101):   # i prend les valeurs 1, 2, ..., 100
    total = total + i     # on ajoute i au total courant
print(total)              # affiche 5050
tour i total après le tour
avant — 0
1 1 1
2 2 3
3 3 6
… … …
100 100 5050

La trace d’exécution : suivre l’évolution des variables tour après tour est un réflexe essentiel.

↺ Retour sur l'activité. Le tableau rempli pour le programme 4 de l’activité était déjà une trace ; total y était un accumulateur, qui valait 10 après le tour 4, et remplacer 5 par 101 dans range(1, 5) donne exactement le programme ci-dessus.

Pour les curieux (facultatif) — Un peu d’histoire

D’après la légende, le mathématicien Carl Friedrich Gauss, encore écolier, aurait trouvé ce résultat en une poignée de secondes en remarquant que \(1+100 = 2+99 = \dots = 101\), et qu’il y a 50 telles paires : \(50 \times 101 = 5050\). L’ordinateur, lui, additionne bêtement… mais très vite.

Boucler à l’intérieur d’une boucle#

Le corps d’une boucle peut contenir… une autre boucle. On parle de boucles imbriquées. La boucle intérieure effectue un tour complet pour chaque valeur de la boucle extérieure.

Exemple — Prévoyez le nombre d’étoiles affichées

for ligne in range(3):
    for colonne in range(4):
        print("*", end="")   # end="" : reste sur la meme ligne
    print()                  # passe a la ligne suivante
Correction

La boucle intérieure fait 4 tours pour chacun des 3 tours de la boucle extérieure. On obtient un rectangle de \(3 \times 4 = 12\) étoiles :

****
****
****

▶ Exercices d'application : exercices 14 à 24 et 42 (les boucles for)

Les boucles non bornées : while#

Parfois, on ne sait pas à l’avance combien de fois répéter : on veut continuer tant qu’une condition reste vraie. C’est la boucle non bornée, la boucle while.

solde = 100
annees = 0
while solde < 200:            # tant que le solde n'a pas double
    solde = solde * 1.05      # +5 % par an
    annees = annees + 1
print(annees, "annees")

Définition 4 — Boucle while

while condition: répète le bloc indenté tant que la condition est vraie. La condition est testée avant chaque tour : si elle est fausse dès le départ, le bloc n’est jamais exécuté.

Le danger : la boucle infinie#

Règle 7 — Faire évoluer la condition

Le bloc d’un while doit modifier, tôt ou tard, une variable de la condition, faute de quoi la condition reste vraie pour toujours : c’est la boucle infinie. Le programme se fige et ne s’arrête plus.

i = 0
while i < 5:
    print(i)
    # OUPS : on a oublie d'augmenter i

Ici i vaut toujours 0, donc i < 5 reste éternellement vrai : le programme affiche 0 sans fin. (Pour l’interrompre : Ctrl + C.) L’oubli de l’incrément est le grand classique de la boucle while.

Prouver qu’une boucle s’arrête : le variant#

Le programme demande explicitement de savoir justifier la terminaison d’une boucle non bornée. L’outil s’appelle le variant de boucle.

Définition 5 — Variant de boucle

Un variant est une quantité entière positive qui décroît strictement à chaque tour de boucle. S’il en existe un, la boucle ne peut pas tourner indéfiniment : une suite d’entiers positifs strictement décroissante ne peut pas se prolonger indéfiniment, donc la boucle finit par s’arrêter.

Exemple — Un compte à rebours

n = 10
while n > 0:
    print(n)
    n = n - 1

La quantité n est un variant : elle est positive tant qu’on entre dans la boucle, et elle diminue de 1 à chaque tour. Elle atteindra donc 0, ce qui rend la condition n > 0 fausse : la boucle se termine.

Règle 8 — for ou while ?

  • on connaît le nombre de tours (parcourir 1 à 100, répéter 10 fois…) \(\rightarrow\) for ;

  • on répète selon une condition dont on ignore quand elle deviendra fausse (jusqu’à ce que l’utilisateur tape « stop », jusqu’à ce que le solde double…) \(\rightarrow\) while.

▶ Exercices d'application : exercices 25 à 30 et 43 (les boucles while)

Les fonctions#

Depuis le début du chapitre, vous écrivez des fonctions en suivant un gabarit ; voyons maintenant ce qu’il contient vraiment. Dès qu’un programme grandit, on a besoin de le découper en morceaux réutilisables, chacun chargé d’une tâche précise. Ces morceaux sont les fonctions. Le programme le dit clairement : la modularisation « permet la réutilisation de programmes et la mise à disposition de bibliothèques ».

Définir et appeler une fonction#

Définition 6 — Fonction

Une fonction est un bloc d’instructions nommé, que l’on définit une fois (mot-clé def) et que l’on appelle ensuite autant de fois qu’on veut. Elle peut recevoir des paramètres (ses entrées) et renvoyer un résultat (mot-clé return).

def aire_rectangle(largeur, hauteur):
    return largeur * hauteur

# appels de la fonction :
print(aire_rectangle(3, 4))       # affiche 12
surface = aire_rectangle(10, 2)   # surface recoit 20

On voit une fonction comme une boîte noire : on lui fournit des valeurs en entrée (les arguments), elle rend une valeur en sortie. Peu importe comment elle travaille à l’intérieur : pour l’utiliser, il suffit de connaître ses entrées et sa sortie.

Règle 9 — return n’est pas print

print affiche une valeur à l’écran (pour un humain) ; return renvoie une valeur au programme (pour la réutiliser dans un calcul). Une fonction qui print mais ne return rien renvoie en réalité la valeur spéciale None, et son résultat ne peut pas être réutilisé. Confondre les deux est une erreur très fréquente.

À retenir — return termine la fonction

Dès que Python rencontre un return, il sort immédiatement de la fonction : les lignes situées après ne sont pas exécutées.

Portée : variables locales et globales#

Règle 10 — Variables locales

Les paramètres et les variables créées à l’intérieur d’une fonction sont locaux : ils naissent à l’appel, meurent au return, et sont invisibles depuis l’extérieur. Deux fonctions peuvent donc utiliser une variable i sans jamais se gêner.

def double(x):
    resultat = 2 * x    # resultat est LOCAL a la fonction
    return resultat

print(double(5))        # 10
print(resultat)         # NameError : resultat n'existe pas ici

Ce cloisonnement est une force : chaque fonction est un petit monde étanche, ce qui rend le programme bien plus facile à comprendre et à corriger.

Spécifier une fonction (au programme)#

Écrire une fonction juste ne suffit pas : il faut dire clairement ce qu’elle fait, ce qu’elle attend et ce qu’elle garantit. C’est la spécification, exigée par le programme.

Définition 7 — Prototype, précondition, postcondition

  • le prototype annonce le nom de la fonction et ses paramètres : racine(x) ;

  • une précondition est une hypothèse sur les arguments, à la charge de l’appelant (ex. : x >= 0) ;

  • une postcondition décrit une garantie sur le résultat (ex. : « renvoie un nombre positif »).

En pratique, on documente une fonction avec une docstring (un texte entre triples guillemets, juste après le def) et on peut vérifier une précondition avec une assertion. On en donne ici une première idée ; le chapitre Spécifier et mettre au point ses programmes y reviendra en détail.

def racine(x):
    """Renvoie la racine carree de x.
    Precondition : x >= 0.
    Postcondition : le resultat au carre redonne x."""
    assert x >= 0, "x doit etre positif"
    return x ** 0.5

Remarque

Une assert qui échoue arrête le programme avec un message clair. C’est un garde-fou précieux : mieux vaut un arrêt net et explicite qu’un résultat faux qui passe inaperçu.

Tester une fonction (au programme)#

Comment être sûr qu’une fonction est correcte ? On la soumet à un jeu de tests : des cas dont on connaît le résultat attendu. En Python, on écrit ces tests avec des assert : si tout se passe bien, le programme ne dit rien ; au premier test faux, il s’arrête.

def maximum(a, b):
    if a > b:
        return a
    return b

assert maximum(3, 5) == 5
assert maximum(5, 3) == 5
assert maximum(4, 4) == 4    # le cas d'egalite : a ne pas oublier

Règle 11 — Un jeu de tests ne prouve rien… mais protège beaucoup

Le programme insiste sur un point subtil : « le succès d’un jeu de tests ne garantit pas la correction d’un programme ». Passer les tests montre seulement que la fonction est juste sur les cas testés. On soigne donc les tests : cas normaux, cas limites (0, valeurs égales, chaîne vide…), cas particuliers.

Trois réflexes à prendre dès aujourd’hui

Pour chaque fonction que vous écrirez cette année, prenez l’habitude de :

  1. écrire une docstring (rôle + précondition + postcondition) ;

  2. poser un garde-fou assert sur la précondition ;

  3. écrire un petit jeu de tests en assert, sans oublier les cas limites.

Ces gestes seront approfondis dans les chapitres Algorithmique : le parcours séquentiel (invariants de boucle) et Spécifier et mettre au point ses programmes (débogage, oracle) — mais on les met en pratique dès maintenant.

Réutiliser le travail des autres : les bibliothèques#

On ne réécrit pas tout soi-même : une bibliothèque (module) regroupe des fonctions déjà écrites et testées. On y accède avec import.

import random
print(random.randint(1, 6))   # un de : entier au hasard entre 1 et 6
print(random.randint(0, 100)) # un entier au hasard entre 0 et 100

Méthode — Utiliser une bibliothèque

Nul besoin de connaître une bibliothèque par cœur : l’essentiel est de savoir lire sa documentation pour trouver la fonction utile et comprendre ce qu’elle attend.

Pour les curieux (facultatif) — En Terminale

Deux chapitres prolongent les fonctions : La récursivité (une fonction peut s’appeler elle-même) et Programmation objet et paradigmes (créer ses propres types de données, avec leurs fonctions).

▶ Exercices d'application : exercices 31 à 34 et 44 (les fonctions : spécifier, tester)

Trouver et corriger ses erreurs#

Personne n’écrit un programme juste du premier coup. Savoir lire un message d’erreur fait partie du métier.

Les principaux types d’erreur#

Type d’erreur Quand ?
SyntaxError le code est mal formé (: ou ) oublié…)
IndentationError indentation incohérente
NameError on utilise un nom qui n’existe pas (ou une faute de frappe)
TypeError opération entre types incompatibles ("a" + 1)
ZeroDivisionError division par zéro

Pour les curieux (facultatif) — Le premier « bug » était un vrai insecte

En 1947, l’équipe du calculateur Mark II, dont fait partie l’informaticienne Grace Hopper, trouve un papillon de nuit coincé dans un relais. Elle le colle dans son cahier de bord avec la mention « premier cas réel de bug trouvé », et Grace Hopper rendra l’anecdote célèbre. Le mot est resté ; « déboguer » (debug), c’est chasser ces bestioles du code.

Lire un message d’erreur#

Quand Python rencontre une erreur, il s’arrête et affiche un message. Ce message impressionne (il est en anglais), mais il est toujours construit de la même façon. Voici un programme age.py où l’on a oublié de convertir la saisie :

age = input("Votre age ? ")
print("Dans un an :", age + 1)

On l’exécute et on tape 16 :

Votre age ? 16
Traceback (most recent call last):
  File "/home/eleve/age.py", line 2, in <module>
    print("Dans un an :", age + 1)
                          ~~~~^~~
TypeError: can only concatenate str (not "int") to str

Ce message se lit ainsi :

  • Traceback (most recent call last): : le programme a commencé à s’exécuter, puis s’est arrêté sur une erreur ;

  • File "/home/eleve/age.py", line 2 : le fichier et le numéro de la ligne où l’erreur s’est produite ;

  • vient ensuite la ligne fautive, recopiée ; en dessous, le signe ^ (entouré de ~) montre l’endroit précis : ici, le + ;

  • la dernière ligne est la plus importante : le type d’erreur (TypeError, voir le tableau ci-dessus), puis le message : « on ne peut concaténer à une str qu’une str, pas un int ».

Le diagnostic suit : age est une chaîne, car input renvoie toujours une chaîne. On corrige avec age = int(input("Votre age ? ")).

Une faute de syntaxe est détectée avant l’exécution : Python refuse le programme sans exécuter la moindre ligne, et le message n’a pas de ligne Traceback, mais il se lit de la même façon. Dans ce programme note.py, il manque le deux-points du if :

note = int(input("Note ? "))
if note >= 10
    print("Admis")

La question « Note ? » n’est même pas posée ; Python affiche :

  File "/home/eleve/note.py", line 2
    if note >= 10
                 ^
SyntaxError: expected ':'

Le ^ pointe juste après 10, là où Python attendait (expected) le :. La présentation varie un peu selon l’éditeur et la version de Python, mais on retrouve toujours le fichier, le numéro de ligne, la ligne fautive et, en dernier, le type d’erreur suivi du message.

Méthode — Quand ça ne marche pas

  1. Lire la dernière ligne du message : le type d’erreur et le message.

  2. Regarder la ligne indiquée, puis la ligne précédente : une parenthèse ou un guillemet non refermé peut être signalé une ligne trop bas.

  3. Vérifier les détails : le : en fin de ligne if, elif, else, for, while, def ; chaque ( a sa ) ; chaque " ouvrant a son " fermant ; l’indentation (4 espaces par niveau).

  4. Si le programme ne s’arrête pas mais donne un mauvais résultat, ajouter un print de contrôle qui affiche les valeurs des variables, par exemple print("i =", i, "total =", total) dans une boucle ; le retirer une fois l’erreur trouvée.

▶ Exercices d'application : exercices 45 et 46 (corriger d’après le message d’erreur)

Pour les curieux (facultatif) — Liens avec d’autres chapitres

  • Juste après. Le résultat surprenant de 0.1 + 0.2 s’expliquera au chapitre Le binaire et l’écriture des nombres, où // et % serviront à convertir un entier en binaire.

  • Plus loin dans l’année. Les chaînes et les range, numérotés à partir de 0, annoncent les tableaux des Types construits ; l’accumulateur deviendra le patron de tous les parcours ; docstrings, assert et tests seront approfondis dans Spécifier et mettre au point ses programmes.

  • En Terminale. Le chapitre Calculabilité montrera qu’aucun programme ne peut décider, pour toute boucle, si elle s’arrête : d’où l’importance de savoir exhiber soi-même un variant.

Bilan — la carte mémoire#

Les six constructions élémentaires du programme, réunies :

Construction À retenir
Séquence les instructions s’exécutent dans l’ordre, de haut en bas
Affectation = « reçoit » : on évalue à droite, on range à gauche
Conditionnelle if/elif/else choisir selon une condition (booléen) ; : + indentation
Boucle bornée for répéter un nombre connu de fois (range)
Boucle non bornée while répéter tant qu’une condition est vraie ; gare à l’infini
Appel de fonction def pour définir, return pour renvoyer ; entrées \(\to\) sortie
Réflexe À retenir
Types de base int, float, str, bool ; gare aux flottants
= contre == affecter contre tester l’égalité
print contre return afficher contre renvoyer pour réutiliser
Terminaison un variant (entier \(\geqslant 0\) qui décroît) garantit l’arrêt
Spécifier / tester docstring, préconditions (assert), jeu de tests

Retour à la situation de départ

  1. Avec une variable temporaire : temp = a, puis a = b, puis b = temp. Sans elle, l’affectation a = b écrase l’ancienne valeur de a, qui est perdue (§ II).

  2. Avec une boucle bornée for i in range(1, 101): et un accumulateur total, initialisé à 0, auquel on ajoute i à chaque tour ; le programme affiche 5050 (§ IV).

  3. Oui : une boucle while dont la condition reste toujours vraie est une boucle infinie. Pour garantir l’arrêt, on exhibe un variant, entier positif qui décroît strictement à chaque tour (§ V).

Erreurs fréquentes#

  • Confondre = et ==. = affecte une valeur, == teste l’égalité. Le réflexe : dans un if, c’est ==.

  • Confondre print et return. print affiche ; return renvoie une valeur réutilisable. Une fonction sans return renvoie None.

  • Oublier le : ou mal indenter. En Python, le bloc est défini par l’indentation ; le : termine la ligne d’un if, for, while, def.

  • Une boucle while qui ne progresse pas. Si la variable de condition n’évolue pas, la boucle est infinie. Le réflexe : un variant qui se rapproche de l’arrêt.

  • Oublier que input renvoie une chaîne. Pour calculer, convertir : int(input(…)).

  • Confondre / et //. / donne un flottant, // le quotient entier ; % donne le reste.

Savoir-faire à maîtriser#

À la fin du chapitre, je sais…

  • créer (affecter) une variable et reconnaître son type (int, float, str, bool) ;

  • écrire une condition (if / elif / else) et une expression booléenne ;

  • écrire une boucle bornée (for) et non bornée (while) ;

  • définir et appeler une fonction avec paramètres et return ;

  • convertir (int / float / str) et lire une entrée (input) ;

  • spécifier (docstring) et tester (assert) une fonction ;

  • justifier qu’une boucle while se termine (variant).