02 - Python (1)

Exercice 0 : QCM – vérification des prérequis

Pour chaque question, une seule réponse est correcte.

1. Après l’exécution de x = 3, que contient la variable x ?

  • A. La chaîne "3"
  • B. L’entier 3
  • C. Le flottant 3.0
  • D. Rien, car x n’a pas été déclarée
Correction

Réponse : B. En Python, x = 3 affecte l’entier 3 à la variable x. Python crée automatiquement la variable lors de la première affectation, sans déclaration préalable.

  • A est faux : pour obtenir la chaîne "3", il faudrait écrire x = "3" (avec des guillemets).
  • C est faux : 3 est un int, pas un float. Pour obtenir 3.0, il faudrait écrire x = 3.0.
  • D est faux : en Python, il n’y a pas de déclaration séparée ; l’affectation crée la variable.

2. Quelle est la valeur de y après l’exécution du code suivant ?

x = 5
y = x + 1
x = 10
  • A. 11
  • B. 6
  • C. 10
  • D. 5
Correction

Réponse : B. Au moment de l’affectation y = x + 1, la variable x vaut 5, donc y reçoit 6. La modification ultérieure de x (ligne 3) ne change pas y : en Python, l’affectation copie la valeur, elle ne crée pas de lien entre les variables.

  • A est faux : c’est l’erreur qui consiste à croire que y est « liée » à x et se recalcule automatiquement (confusion avec un tableur).
  • C est faux : y n’a jamais reçu la valeur de x après sa modification.
  • D est faux : y vaut x + 1, pas x.

3. Que produit print(type(3 / 1)) ?

  • A. <class 'int'>
  • B. <class 'float'>
  • C. <class 'str'>
  • D. Une erreur
Correction

Réponse : B. En Python, l’opérateur / (division) renvoie toujours un float, même si le résultat est entier. Ainsi 3 / 1 vaut 3.0.

  • A est faux : pour obtenir un int, il faudrait utiliser la division entière 3 // 1.
  • C est faux : le résultat d’une division n’est pas une chaîne.
  • D est faux : la division par 1 est tout à fait valide.

4. Quel est l’affichage produit par le code suivant ?

a = 2
b = 3
a = b
b = a
print(a, b)
  • A. 2 3
  • B. 3 2
  • C. 3 3
  • D. 2 2
Correction

Réponse : C. Après a = b, la variable a vaut 3. Ensuite, b = a affecte à b la valeur actuelle de a, qui est 3. Les deux variables valent donc 3.

  • B est faux : c’est l’erreur classique de croire que ces deux lignes échangent les valeurs (il faudrait une variable temporaire ou l’écriture simultanée a, b = b, a).
  • A est faux : a a été modifié à la ligne 3.
  • D est faux : b a été modifié à la ligne 4.

Exercice 1

On exécute la séquence suivante :

x = 5
y = x + 1
x = 10
print(y)

Produit-elle l’affichage de la valeur 6 ou de la valeur 11 ? Justifier en indiquant la trace de l’état d’exécution de ce programme.

Correction

Le programme affiche 6. Trace de l’exécution :

LigneInstructionxy
1x = 55
2y = x + 156
3x = 10106
4print(y)106

À la ligne 2, y reçoit la valeur 5 + 1 = 6. Modifier x ensuite ne change pas y : l’affectation copie la valeur, elle ne crée pas de lien dynamique.

Exercice 2

Déterminer la valeur des expressions suivantes sachant que dans l’état d’exécution actuel du programme, les contenus respectifs des variables x et y sont \(4\) et \(5\) :

y + 3
x + 3
x + y
x * x
y == 5
x == 3 and y == 5
x == 3 or y == 5
Correction

Avec x = 4 et y = 5 :

ExpressionValeurType
y + 38int
x + 37int
x + y9int
x * x16int
y == 5Truebool
x == 3 and y == 5Falsebool
x == 3 or y == 5Truebool

Pour l’avant-dernière : x == 3 vaut False, et False and ... vaut False quel que soit le second opérande (évaluation paresseuse).

Pour la dernière : x == 3 vaut False, mais y == 5 vaut True, donc False or True vaut True.

Exercice 3

Les suites de symboles suivants sont-elles des instructions ou des expressions ? Justifier la réponse.

x
x = y
x = y + 3
x + 3
print(x + 3)
x == a
x == a and y == b
Correction
CodeNatureExplication
xExpressionÉvalue la valeur contenue dans x
x = yInstructionAffectation : modifie l’état du programme
x = y + 3InstructionAffectation (le membre droit y + 3 est une expression)
x + 3ExpressionCalcule une valeur sans modifier l’état
print(x + 3)InstructionAppel de fonction produisant un effet (affichage)
x == aExpressionComparaison : évalue un booléen
x == a and y == bExpressionComparaison composée : évalue un booléen

Règle : une expression produit une valeur ; une instruction modifie l’état du programme (affectation, affichage, etc.).

Exercice 4

Quel est le résultat de chacun des deux scripts suivants. Expliquer.

Script 1

x, y, z = 4, 0, 0
if x == 4:
    y = 1
else:
    y = 2
    z = 3
print(x, y, z)

Script 2

x, y, z = 4, 0, 0
if x == 4:
    y = 1
else:
    y = 2
z = 3
print(x, y, z)
Correction

Script 1 : affiche 4 1 0.

Puisque x == 4 est vrai, seul le bloc if est exécuté : y = 1. Le bloc else (contenant y = 2 et z = 3) est ignoré. Donc z reste à 0.

Script 2 : affiche 4 1 3.

Puisque x == 4 est vrai, le bloc if est exécuté : y = 1. L’instruction z = 3 n’est pas dans le else (elle n’est pas indentée sous le else), donc elle est exécutée dans tous les cas.

Point clé : en Python, l’indentation détermine quelles instructions font partie d’un bloc. Le déplacement d’une seule ligne change complètement le comportement du programme.

Exercice 5

Écrire un programme qui demande à l’utilisateur de saisir un nombre entier et qui renvoie en sortie un affichage indiquant s’il est divisible ou pas par 7.

Correction
n = int(input("Entrez un nombre entier : "))
if n % 7 == 0:
    print(f"{n} est divisible par 7")
else:
    print(f"{n} n'est pas divisible par 7")

On utilise l’opérateur modulo % : si le reste de la division de n par 7 est nul, alors n est divisible par 7.

Tests : 14 → divisible ; 15 → pas divisible ; 0 → divisible ; -7 → divisible.

Exercice 6

  1. Que fait le programme suivant ? Le nom des variables est-il judicieusement choisi ?

     a = int(input())
     b = int(input())
     c = int(input())
     d = int(input())
     if b == 0 or d == 0:
         print("Dénominateur nul interdit")
     else:
         print(a * d + c * b)
         print(b * d)
    
  2. Saisir et tester ce programme en choisissant des noms de variables explicites et en indiquant à l’utilisateur ce qu’il doit saisir.

  1. Commenter chaque ligne pour expliquer son rôle.
Correction

1. Le programme calcule la somme de deux fractions \(\frac{a}{b} + \frac{c}{d} = \frac{a \times d + c \times b}{b \times d}\). Les noms a, b, c, d ne sont pas explicites : on ne comprend pas qu’il s’agit de numérateurs et dénominateurs.

2. Version améliorée :

# Somme de deux fractions
num1 = int(input("Numérateur de la première fraction : "))
den1 = int(input("Dénominateur de la première fraction : "))
num2 = int(input("Numérateur de la seconde fraction : "))
den2 = int(input("Dénominateur de la seconde fraction : "))

if den1 == 0 or den2 == 0:
    print("Dénominateur nul interdit")
else:
    print(f"Numérateur : {num1 * den2 + num2 * den1}")
    print(f"Dénominateur : {den1 * den2}")

3. Commentaires : chaque input saisit un des quatre nombres formant les deux fractions. La condition vérifie qu’aucun dénominateur n’est nul. Le calcul applique la formule de la somme de deux fractions.

Exercice 7

  1. Qu’appelle-t-on factorielle d’un entier naturel n ? Que vaut factorielle de 0 (notée 0!) ? Voir : http://fr.wikipedia.org/wiki/Factorielle

  2. Voici un script permettant de calculer 5! :

     f = f * 1
     f = f * 2
     f = f * 3
     f = f * 4
     f = f * 5
     print(f)
    

    Saisir ce script, l’enregistrer sous le nom factorielle.py et l’exécuter. Quel est le problème ? Comment le régler ? Donner alors la valeur de 5!.

Correction

1. La factorielle d’un entier naturel \(n\), notée \(n!\), est le produit de tous les entiers de \(1\) à \(n\) : \(n! = 1 \times 2 \times \cdots \times n\). Par convention, \(0! = 1\).

2. Le problème est que f n’est pas initialisée avant d’être utilisée : Python lève une erreur NameError: name 'f' is not defined. Il faut ajouter f = 1 au début.

f = 1       # initialisation
f = f * 1   # f = 1
f = f * 2   # f = 2
f = f * 3   # f = 6
f = f * 4   # f = 24
f = f * 5   # f = 120
print(f)    # affiche 120

Donc \(5! = 120\).

Exercice 8

En utilisant la fonction random(), écrire un programme qui affiche aléatoirement pile ou face de façon équiprobable. On pensera à importer le paquet random et à demander l’aide help("random"), les différentes fonctions étant classées par ordre alphabétique.

Correction
import random

if random.random() < 0.5:
    print("pile")
else:
    print("face")

random.random() renvoie un flottant aléatoire dans \([0 ; 1[\). La probabilité d’obtenir une valeur inférieure à 0.5 est exactement \(\frac{1}{2}\), d’où l’équiprobabilité.

Variante plus concise :

import random
print(random.choice(["pile", "face"]))

Exercice 9

Écrire un programme qui demande en entrée à l’utilisateur un nombre (qui peut être décimal) et renvoie en sortie un affichage pour dire si ce nombre est positif, négatif ou nul. Aide : elif.

Correction
x = float(input("Entrez un nombre : "))
if x > 0:
    print(f"{x} est positif")
elif x < 0:
    print(f"{x} est négatif")
else:
    print("Le nombre est nul")

On utilise float (et non int) car le nombre peut être décimal. La structure if / elif / else couvre les trois cas mutuellement exclusifs.

Tests : 3.5 → positif ; -2 → négatif ; 0 → nul.

Exercice 10

Écrire un programme qui demande en entrée à l’utilisateur un nombre (qui peut être décimal) et renvoie en sortie un affichage pour dire si ce nombre appartient à l’intervalle [2; 8].

Réaliser trois scripts en utilisant trois méthodes :

  • imbrication de structures conditionnelles ;
  • le mot-clé and dans la condition ;
  • le mot-clé or dans la condition.
Correction

Méthode 1 : imbrication

x = float(input("Entrez un nombre : "))
if x >= 2:
    if x <= 8:
        print(f"{x} appartient à [2; 8]")
    else:
        print(f"{x} n'appartient pas à [2; 8]")
else:
    print(f"{x} n'appartient pas à [2; 8]")

Méthode 2 : and

x = float(input("Entrez un nombre : "))
if x >= 2 and x <= 8:
    print(f"{x} appartient à [2; 8]")
else:
    print(f"{x} n'appartient pas à [2; 8]")

Méthode 3 : or (sur la condition de non-appartenance)

x = float(input("Entrez un nombre : "))
if x < 2 or x > 8:
    print(f"{x} n'appartient pas à [2; 8]")
else:
    print(f"{x} appartient à [2; 8]")

La méthode 3 utilise or pour tester la non-appartenance : \(x \notin [2 ; 8]\) équivaut à \(x < 2\) ou \(x > 8\) (loi de De Morgan).

Tests : 1 → non ; 2 → oui ; 5 → oui ; 8 → oui ; 9 → non.

Exercice 11

Écrire un programme qui, étant donnée une équation du second degré, détermine, si elles existent, le nombre de ses racines réelles et qui les calcule.

L’entrée de ce programme sera l’équation de la forme \(ax² + bx + c\) donnée sous la forme de ses coefficients \(a\), \(b\) et \(c\) de type float.

La sortie sera l’affichage du nombre de solutions et, quand elles existent, de leurs valeurs.

Une variable delta sera utilisée pour stocker la valeur du discriminant et sa valeur sera affichée.

Pour terminer, proposer un jeu de tests satisfaisant pour valider le bon fonctionnement du programme.

Correction
import math

a = float(input("Coefficient a : "))
b = float(input("Coefficient b : "))
c = float(input("Coefficient c : "))

delta = b**2 - 4 * a * c
print(f"Discriminant : {delta}")

if delta > 0:
    x1 = (-b - math.sqrt(delta)) / (2 * a)
    x2 = (-b + math.sqrt(delta)) / (2 * a)
    print(f"Deux solutions : x1 = {x1} et x2 = {x2}")
elif delta == 0:
    x0 = -b / (2 * a)
    print(f"Une solution double : x0 = {x0}")
else:
    print("Pas de solution réelle")

Jeu de tests :

\(a\)\(b\)\(c\)\(\Delta\)Solutions attendues
1-321\(x_1 = 1\), \(x_2 = 2\)
1-210\(x_0 = 1\) (double)
111-3Pas de solution réelle
2-10124\(x_1 = 2\), \(x_2 = 3\)

Ces tests couvrent les trois cas (\(\Delta > 0\), \(\Delta = 0\), \(\Delta < 0\)).

Exercice 12 (Pour les costauds !)

Le but de cet exercice est d’écrire un programme qui demande à l’utilisateur une date comprise entre le \(1^{er}\) janvier 1901 et le 31 décembre 2099 et qui indique le nombre de jours qui se sont écoulés entre le \(1^{er}\) janvier 1901 et cette date choisie.

Une bonne approximation de ce nombre est \[(a - 1901) \times 365 + (m - 1) \times 30 + j - 1.\]

Mais il faut lui ajouter deux termes correctifs.

  • Le premier est dû au fait que tous les mois n’ont pas 30 jours. On peut montrer que ce terme correctif vaut m // 2 si \(m ∈ \{1 ; 2\}\) et (m + m // 8) // 2 - 2 si \(m ∈ \{3 ; … ; 12\}\).
  • Le second est dû aux années bissextiles. On peut montrer que ce terme correctif vaut (a - 1900) // 4 - 1 si \(a\) est multiple de \(4\) et \(m ∈ \{1 ; 2\}\) et (a - 1900) // 4 sinon.
  1. Écrire un programme qui demande à l’utilisateur trois nombres formant une date (resp. jour / mois / année) comprise entre le \(1^{er}\) janvier 1901 et le 31 décembre 2099 et qui indique le nombre de jours écoulés depuis le \(1^{er}\) janvier 1901 en tenant compte les informations données ci-dessus.
  1. Écrire un programme qui demande à l’utilisateur deux dates et indique le nombre de jours écoulés entre ces deux dates.
Correction

1. Calcul du nombre de jours depuis le 1er janvier 1901 :

j = int(input("Jour : "))
m = int(input("Mois : "))
a = int(input("Année : "))

# Approximation de base
nb_jours = (a - 1901) * 365 + (m - 1) * 30 + j - 1

# Correctif mois
if m <= 2:
    nb_jours += m // 2
else:
    nb_jours += (m + m // 8) // 2 - 2

# Correctif années bissextiles
if a % 4 == 0 and m <= 2:
    nb_jours += (a - 1900) // 4 - 1
else:
    nb_jours += (a - 1900) // 4

print(f"Nombre de jours depuis le 1er janvier 1901 : {nb_jours}")

2. Pour l’écart entre deux dates, on calcule le nombre de jours pour chacune et on fait la différence (en valeur absolue) :

def jours_depuis_1901(j, m, a):
    nb = (a - 1901) * 365 + (m - 1) * 30 + j - 1
    if m <= 2:
        nb += m // 2
    else:
        nb += (m + m // 8) // 2 - 2
    if a % 4 == 0 and m <= 2:
        nb += (a - 1900) // 4 - 1
    else:
        nb += (a - 1900) // 4
    return nb

print("Première date :")
j1 = int(input("Jour : "))
m1 = int(input("Mois : "))
a1 = int(input("Année : "))

print("Seconde date :")
j2 = int(input("Jour : "))
m2 = int(input("Mois : "))
a2 = int(input("Année : "))

ecart = abs(jours_depuis_1901(j2, m2, a2) - jours_depuis_1901(j1, m1, a1))
print(f"Écart : {ecart} jours")