Exo Révision

Identification

Infoforall

25 - Fiche de révision sur Python


Cette page permet de réviser les notions de Python vues en 1er.

Si vous voulez les versions papier :

Rappels des notions fondamentales en Python : .PDF et .ODT

Exercices de révisions : .PDF et .ODT

1 - Les exercices

01° Expliquer la signification des 3 opérateurs suivants en Python :

  1. ==
  2. !=
  3. =

...CORRECTION...

  1. ==
  2. Il s'agit de l'opérateur d'égalité : il renvoie un booléen valant True si les termes de gauche et de droite sont identiques.

  3. !=
  4. Il s'agit de l'opérateur de différence ou d'inégalité : il renvoie un booléen valant True si les termes de gauche et de droite sont différents.

  5. =
  6. Il s'agit de l'opérateur d'affectation : il ne renvoie rien mais affecte la valeur évaluée à droite à une variable dont le nom se trouve à gauche. L'affectation se fait donc de la droite vers la gauche.

02° Que contiennent a, b et c au fur et à mesure de ce programme ?

1 2 3 4 5 6
a = 19 b = 20 c = a == b c = a != b c = a+1 == b a = a + 1

...CORRECTION...

1 2
a = 19 b = 20

Facile : a référence 19 et b référence 20.


Pour la suivante, il faut savoir que l'opérateur d'affectation = est celui qui a la priorité la plus basse : on finit toujours par lui. On voit alors que c référence le résulat de l'opérateur d'égalité :

3
c = a == b

Puisque 19 et 20 ne sont pas égaux, c référence False.


c référence le résulat de l'opérateur de différence / inégalité :

4
c = a != b

Puisque 19 et 20 sont bien différents, c référence True.


Plus complexe : cette fois, il faut savoir que l'opération + est prioritaire sur == qui est prioritaire sur =.

5
c = a+1 == b

Puisque 19+1 et 20 sont bien égaux, c référence True.


On commence par l'opérateur + :

6
a = a + 1

C'est une incrémentation : on commence par évaluer à droite a + 1 qui donne 20 et on fait ensuite l'affectation vers a.


03° Quels sont les types des différentes valeurs ci-dessous ? Quelle ligne fonctionne en Python mais risquerait de poser problème dans d’autres langages de programmation ?

1 2 3 4 5 6
a = 19 b = 19.0 c = (a, b) d = [a, b] e = {'alice':a, 'bob':b} f = 'alice'

...CORRECTION...

1 2 3 4 5 6
a = 19 # type int pour integers, les entiers b = 19.0 # type float pour virgule flottante. N'encode PAS tous les réels. c = (a, b) # type tuple, un conteneur IMMUABLE/IMMUTABLE. d = [a, b] # type list, un tableau MUABLE/MUTABLE. e = {'alice':a, 'bob':b} # type dict, un dictionnaire MUABLE/MUTABLE. f = 'alice' # type str, un string IMMUABLE/IMMUTABLE.

On notera que les cases des types str, tuple et list sont accessibles en utilisant des indices (les numéros de cases).

On notera que les cases du type dict sont accessibles en utilisant des indices (les numéros de cases).

Tableau statique

On notera que le type list permet de représenter des tableaux (statiques et dynamiques) mais qu'ils ont une particularité en Python : on peut mettre des données de type différents dans les différentes cases. Ici int en case d'indice 0 et float en case d'indice 1.

Normalement, un tableau ne peut contenir qu'un seul type de données : un tableau d'entiers ou un tableau de floats par exemple.

Savez-vous pourquoi Python permet de mélanger les types ?

04° Comment accéder à la valeur de a contenue dans c d et e ?

...CORRECTION...

1 2 3
c[0] # Tuple donc indice d[0] # tableau list donc indice e['alice'] # dict donc clé

05° Quels sont les indices disponibles dans f? ?

...CORRECTION...

f est un string contenant 5 caractères.

Les indices sont donc 0-1-2-3-4.

1
f = 'alice' 01234

06° A quoi servent les fonctions natives str(), int(), list() et tuple() ?

...CORRECTION...

Elles servent à faire du transtypage : tenter de créer une copie de l'ancienne donnée en la transformer vers le nouveau format.

07° Fournir le contenu des variables c, d, e et t lors de l’exécution :

1 2 3 4 5 6
a = 2 b = '5' c = a * b d = str(a) + b e = a * int(b) t = list('alice')

...CORRECTION...

1 2 3 4 5 6
a = 2 # 2 donc int b = '5' # '5' donc str c = a * b # str '55' car 2*'5' (répétition) d = str(a) + b # str '25' car '2'+'5' (concaténation) e = a * int(b) # int 10 car 2*5 (multiplication) t = list('alice') # list ['a', 'l', 'i', 'c', 'e']

08° Fournir les contenus des tableaux suivants :

1 2 3 4 5
t1 = list( range(5) ) t2 = list( range(2, 5) ) t3 = list( range(2, 50, 10) ) t4 = list( range(2, 52, 10) ) t5 = list( range(50, 0, -10) )

...CORRECTION...

1 2 3 4 5
t1 = list( range(5) ) On transmet la valeur "presque finale", la borne finale exlue. On obtient donc [0, 1, 2, 3, 4]. t2 = list( range(2, 5) ) On transmet la valeur initiale puis la "presque finale". On obtient donc [2, 3, 4]. t3 = list( range(2, 50, 10) ) On transmet la valeur "presque finale", la borne finale exlue et le pas. On obtient donc [2, 12, 22, 32, 42]. t4 = list( range(2, 52, 10) ) On transmet la valeur "presque finale", la borne finale exlue. On obtient donc toujours [2, 12, 22, 32, 42]. t5 = list( range(50, 0, -10) ) On transmet la valeur "presque finale", la borne finale exlue. On obtient donc toujours [50, 40, 30, 20, 10].

09° Pour chacune des variables n, rep, k et x, dire s’il s’agit d’une variable globale ou locale :

1 2 3 4 5 6 7
def calcul(n) : rep = 0 for k in range(1, n) : rep = rep + k return rep*10 x = calcul(5)

...CORRECTION...

Variable globale : variable déclarée directement dans le programme. Elle est permanente jusqu'à que le programme soit interrompu.

Variable locale : variable déclarée dans une fonction. Elle est temporaire : elle n'existe pas avant l'appel à la fonction et disparait lorsque la fonction exécute son return.

1 2 3 4 5 6 7
def calcul(n) : # n est locale rep = 0 # rep est locale for k in range(1, n) : # k est locale rep = rep + k # rep est locale return rep*10 x = calcul(5) # x est globale

10° Sur quelle ligne se trouve l’appel de la fonction calcul() ? Sur quelle ligne se trouve la déclaration ou définition de la fonction calcul() ? Quelle est la différence entre appel et déclaration ?

...CORRECTION...

L'appel se trouve en ligne 7 : un appel consiste à utiliser réellement la fonction, en lui envoyant des arguments qu'elle stockera dans ses paramètres.

La déclaration se trouve en ligne 1 : on signale à Python que la fonction se trouve en ligne s'il la cherche.

11° Donner les lignes suivies par l’interpréteur Python et le contenu progressif de la mémoire sur le programme Q09.

1 2 3 4 5 6 7
def calcul(n) : rep = 0 for k in range(1, n) : rep = rep + k return rep*10 x = calcul(5)

...CORRECTION...

1 2 3 4 5 6 7
def calcul(n) : rep = 0 for k in range(1, n) : rep = rep + k return rep*10 x = calcul(5)

L01 : déclaration de la fonction.

L07 : appel de la fonction en envoyant l'argument 5.

L01 : on stocke 5 dans le paramètre n.

L02 : on initialise rep à 0.

L03-L04 : 1er tour avec k à 1, et incrémentation de rep à 0+1 = 1

L03-L04 : 2e tour avec k à 2, et incrémentation de rep à 1+2 = 3

L03-L04 : 3e tour avec k à 3, et incrémentation de rep à 3+3 = 6

L03-L04 : 4e tour avec k à 4, et incrémentation de rep à 6+4 = 10

L05 : on renvoie 10*10 = 100 vers la ligne 07

L07 : on réalise l'affectation et x référence maintenant 100.

12° Quelqu’un modifie en ligne 03 le nom de k en x. Expliquer si cela va causer une erreur ou pas.

1 2 3 4 5 6 7
def calcul(n) : # n est locale rep = 0 # rep est locale for x in range(1, n) : # x est locale rep = rep + x # rep est locale return rep*10 x = calcul(5) # x est globale

...CORRECTION...

Aucune erreur : Python va travailler comme si nous avions tapé ceci :

1 2 3 4 5 6 7
def calcul(n) : # n est locale rep = 0 # rep est locale for x_local in range(1, n) : # x est locale rep = rep + x_local # rep est locale return rep*10 x_global = calcul(5) # x est globale

Pour lui, il s'agit donc bien de deux variables différentes, aucun problème d'ambigüité.

Il n'y aura aucune erreur et c'est bien pratique : cela vous évite d'avoir à chercher le nom de toutes les variables dans le programme avant de choisir les noms de variables pour vos nouvelles fonctions.

13° Donner la table de vérité du and et du or.

...CORRECTION...

Voici la table de vérité de l'opérateur ET :

Valeur de a Valeur de b a and b
False False False
False True False
True False False
True True True

A RETENIR : le ET est VRAI uniquement lorsque toutes les entrées sont à VRAI.

Voici la table de vérité de l'opérateur OU :

Valeur de a Valeur de b a or b
False False False
False True True
True False True
True True True

A RETENIR : le OU est FAUX uniquement lorsque toutes les entrées sont à FAUX.

Notez bien que le OU logique n'est pas le OU habituellement utilisé en français. Le OU de 'fromage ou dessert' (sous entendu l'un ou l'autre, pas les deux) se nomme le XOR, le OU eXclusif.

Voici sa table de vérité :

Valeur de a Valeur de b a xor b
False False False
False True True
True False True
True True False

14° Compléter le programme pour que le booléen c contienne True si les deux notes sont strictement supérieures à 10. A votre avis, quelle est l’erreur courante qu’on voit sur les copies ?

1 2 3
note1 = int( input() ) note2 = int( input() ) c = ...

...CORRECTION...

1 2 3
note1 = int( input() ) note2 = int( input() ) c = note1 > 10 and note2 > 10

Cette version est correct car Python attend une condition à gauche du and et une autre condition à droite du and.

L'erreur courante a ne pas faire est la suivante : on écrit le code Python comme on le pense en français : note1 et note 2 sont supérieures à 10, ce qui donne :

3
c = note1 and note2 > 10 # FAUX ATTENTION

Pourquoi est-ce faux : c'est simple. Python va transtyper note1 en booléen, comme si vous aviez noté ceci :

3
c = bool(note1) and bool(note2 > 10) # FAUX ATTENTION

A SAVOIR PAR COEUR : en Python, 0, vide ou None sont transtypés en False. Tout le reste est True !

Même si note1 vaut 9, la condition de gauche sera donc évaluée à True car bool(9) est True. Bref, ca ne fonctionne pas comme vous le voulez.

15° Quelqu’un vous donne le prototype ci-dessous. Comment décrire cela en français (avec des phrases) :

moyenne(t:list) -> tuple

...CORRECTION...

moyenne() est une fonction qui attend qu'on lui envoie un tableau de type list qu'elle stockera dans un paramètre nommé t.

Après son exécution, sa réponse sera une donnée de type tuple.

16° Quelqu’un vous donne le prototype ci-dessous. Comment décrire cela en français (avec des phrases) :

moyenne(t:'list[int] NON VIDE') -> tuple

...CORRECTION...

moyenne() est une fonction qui attend qu'on lui envoie un tableau de type list qui devra être NON VIDE (avoir au moins un élément) et qui contiendra uniquement des entiers. La fonction stockera dans un paramètre nommé t.

Après son exécution, sa réponse sera une donnée de type tuple.

PRECONDITIONS

Il s'agit du nom qu'on donne aux conditions supplémentaires, en plus du seul type. Ici, il s'agit donc de NON VIDE.

17° Réaliser une fonction moyenne() précédente. La fonction devra renvoyer un tuple contenant la moyenne des valeurs et le nombre de valeurs contenues dans le tableau. Comment se nomme cette condition sur la sortie ?

...CORRECTION...

Version 1 avec un parcours par indices :

1 2 3 4 5 6 7 8
def moyenne(t:'list[int] NON VIDE') -> tuple: """Renvoie la moyenne des notes et le nombre de notes""" somme = 0 # on initialise la variable de stockage for i in range(len(t)): # pour tous les indices possibles dans t somme = somme + t[i] # on incrémente de la nouvelle note lue moy = somme / len(t) return (moy, len(t))

Version 2 avec un parcours par valeurs :

1 2 3 4 5 6 7 8
def moyenne(t:'list[int] NON VIDE') -> tuple: """Renvoie la moyenne des notes et le nombre de notes""" somme = 0 # on initialise la variable de stockage for v in t: # pour toutes les valeurs contenues dans t somme = somme + v # on incrémente de la nouvelle note lue moy = somme / len(t) return (moy, len(t))

18° Que doit-il se passer si on passe un appel en respectant les préconditions ? Que peut-il se passer si on ne les respecte pas ?

...CORRECTION...

Il y a donc une sorte de contrat de confiance entre utilisateur et concepteur :

  • L'utilisateur est le garant du respect des préconditions lors des appels
  • Le concepteur garantit que la postcondition est alors vérifiée (sous condition du respect des préconditions donc).

Premier cas : l'utilisateur respecte les préconditions

Dans ce cas, l'utilisateur peut concevoir le reste de son programme en considérant que la postcondition est vraie : le concepteur de la fonction s’y est engagé.

Si la fonction donne une mauvaise réponse ou provoque une exception, c'est la faute du concepteur car l'utilisateur a envoyé des données respectant les préconditions.

Deuxième cas : l'utilisateur ne respecte pas les préconditions

Dans ce cas, on ne peut pas tenir compte de la postcondition.

La fonction peut

  • fonctionner correctement par hasard ou
  • donner une mauvaise réponse ou
  • provoquer une erreur.

En tous cas, c'est clairement la faute de l'utilisateur : il a utilisé la fonction hors des clous.

19° Comment résumer mathématiquement la relation entre préconditions et postconditions ?

...CORRECTION...

PRECONDITONS POSTCONDITONS

Notez bien qu'il s'agit de l'implication et pas de l'équivalence.

20-A° Réaliser une fonction-prédicat est_valide(t:list[int]) → bool qui renvoie True si toutes les notes contenus dans t sont bien entre 0 et 20. Réaliser la documentation de votre fonction. Vous utiliserez un parcours par indices pour réaliser la fonction.

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def est_valide(t:'list[int]') -> bool: """Précidat qui renvoie True si toutes les notes sont dans [0, 20]""" for i in range(len(t)): # Pour tous les indices disponibles sur t if t[i] < 0 or t[i] > 20: # Si la note actuelle n'est pas bonne return False # on répond que le tableau pose problème return True # si on arrive ici, c'est que tout est bon. # Tests rep = est_valide([10, 15, 22, 11]) print(rep) rep = est_valide([10, 15, 2, 11]) print(rep)

20-B° Même question mais vous utiliserez un parcours par valeurs pour réaliser la fonction.

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def est_valide(t:'list[int]') -> bool: """Précidat qui renvoie True si toutes les notes sont dans [0, 20]""" for v in t: # Pour tous les indices disponibles sur t if v < 0 or v > 20: # Si la note actuelle n'est pas bonne return False # on répond que le tableau pose problème return True # si on arrive ici, c'est que tout est bon. # Tests rep = est_valide([10, 15, 22, 11]) print(rep) rep = est_valide([10, 15, 2, 11]) print(rep)

20-C° Même question mais avec le prototype suivant : est_valide(t:dict[(str,int)]) → bool

Exemple d’appel

est_valide( {'alice':10, 'bob':2, 'charles':22} )

...CORRECTION...

En utilisant un parcours par clés explicite ( avec keys() ):

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def est_valide(d:'dict[(str,int)]') -> bool: """Précidat qui renvoie True si toutes les notes sont dans [0, 20]""" for c in d.keys(): # Pour toutes les clés disponibles sur d if d[c] < 0 or d[c] > 20: # Si la note actuelle n'est pas bonne return False # on répond que le tableau pose problème return True # si on arrive ici, c'est que tout est bon. # Tests rep = est_valide({'alice':10, 'bob':2, 'charles':22}) print(rep) rep = est_valide({'alice':10, 'bob':2, 'charles':12}) print(rep)

En utilisant un parcours par clés implicite ( sans keys() ):

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def est_valide(d:'dict[(str,int)]') -> bool: """Précidat qui renvoie True si toutes les notes sont dans [0, 20]""" for c in d: # Pour toutes les clés disponibles sur d if d[c] < 0 or d[c] > 20: # Si la note actuelle n'est pas bonne return False # on répond que le tableau pose problème return True # si on arrive ici, c'est que tout est bon. # Tests rep = est_valide({'alice':10, 'bob':2, 'charles':22}) print(rep) rep = est_valide({'alice':10, 'bob':2, 'charles':12}) print(rep)

En utilisant un parcours par valeurs ( avec values() ):

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def est_valide(d:'dict[(str,int)]') -> bool: """Précidat qui renvoie True si toutes les notes sont dans [0, 20]""" for v in d.values(): # Pour toutes les clés disponibles dans d if v < 0 or v > 20: # Si la note actuelle n'est pas bonne return False # on répond que le tableau pose problème return True # si on arrive ici, c'est que tout est bon. # Tests rep = est_valide({'alice':10, 'bob':2, 'charles':22}) print(rep) rep = est_valide({'alice':10, 'bob':2, 'charles':12}) print(rep)

En utilisant un parcours par couples (cle, valeur) ( sans items() ):

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def est_valide(d:'dict[(str,int)]') -> bool: """Précidat qui renvoie True si toutes les notes sont dans [0, 20]""" for (c, v) in d.items(): # Pour toutes les clés et valeurs disponibles dans d if v < 0 or v > 20: # Si la note actuelle n'est pas bonne return False # on répond que le tableau pose problème return True # si on arrive ici, c'est que tout est bon. # Tests rep = est_valide({'alice':10, 'bob':2, 'charles':22}) print(rep) rep = est_valide({'alice':10, 'bob':2, 'charles':12}) print(rep)

2 - FAQ

Comment encode-t-on les integers déjà ?

Pourquoi est-ce que l'encodage des floats est parfois approximatif ?

Tableaux statiques et tableaux dynamiques ? Pourquoi pas juste liste comme c'est le type list ?

Activité publiée le 05 09 2024
Dernière modification : 05 09 2024
Auteur : ows. h.