TP M1207 n°3 - Partie 2 sur 2 - Durée 2h

Révisions, Listes et Fichiers en Python 3

python Logo

Préambule

Un peu de compassion

Oui c'est déclicat de manipuler des langages différents... 🥵

Mais n'oubliez pas : le pseudo code reste le même, une variable reste une variable, afficher reste afficher, un for reste un for, un while reste un while, un if un if etc. 🤗

Image de joie

Image de joie

Révisions

Votre programme devra avoir exactement, i.e. au caractère près, le même comportement (comme sur chaque exemple donné).

Un while pour la saisie du n qui convient.

Puis une fois un bon n saisi, un for pour afficher la suite attendue, i.e. une répétition de i+"..." affichés sur une ligne pour i allant de 1 à n-1.

Liste (List) Python3 (proche tableau)

Une liste Python 3 (type/classe List) est une structure de données permettant de stocker plusieurs éléments de manière ordonnées comme un tableau en Java à la différence que la taille de la liste est dynamique et plusieurs éléments de différents types peuvent être stockés.

liste1 = [e1, e2 , e3] crée une liste liste1 avec 3 éléments e1, e2 et e3.

len(liste1) retourne le nombre d'éléments de la liste liste1.

liste1 + liste2 retourne la liste concaténée de liste1 avec liste2. La concaténation multiple est possible aussi liste1 * n (avec n un entier)

Comme pour un tableau Java les éléments d'une liste Python 3 sont indicés de 0 (le premier élément) à longueur de la liste moins un. L'indice du dernier élément d'une liste liste1 est len(liste1)-1.

Si i est positif ou nul, liste1[i] retourne l'élément d'indice i. Si i est négatif on retourne en partant de la droite, d'où liste1[-1] retournant le dernier élément de la liste liste1, liste1[-2] retourneraient l'avant dernier.

liste1[i:j] renvoie la sous liste entre les éléments d'indice i et j-1.

liste1[i:j:k] renvoie la sous liste entre les éléments d'indice i et j-1 par pas de k.

liste1[i:] renvoie la sous liste composée des éléments de liste1 à partir de l'indice i.

liste1[:j] renvoie la sous liste composée des éléments de liste1 jusqu'à l'indice j.

liste1[::-1] permet donc de renvoyer la liste1 inversée.

Une liste est modifiable.

Voici quelques méthodes supplémentaires.

liste1.append(elt) ajoute l'élément elt à la fin de la liste liste1.

liste1.pop() supprime et retourne l'élément en dernière position de la liste liste1.

liste1.insert(i,elt) insère (ajoute) l'élément elt en position i dans la liste liste1.

del liste1[i] supprime l'élément d'indice i dans la liste liste1.

liste1.remove(elt) supprime la première occurrence de l'élément elt de la liste liste1.

liste1.count(elt) compte le nombre de fois où l'élément elt est présent dans la liste liste1.

liste1.extend(liste2) concatène la liste liste2 à la fin de la liste liste1. Èquivalent donc à liste1=liste1+liste2.

Pour parcourir une liste on peut utiliser le for comme ceci :

for elt in liste1:
  print(type(elt))

Manipulation de fichiers en Python3

Pour sauvegarder des informations entre plusieurs lancements d'un programme vous pouvez sauvegarder des informations dans des fichiers. La manipulation de fichiers est très utile.

En Python 3, pour manipuler un fichier on utilise la fonction open qui prend deux paramètres : le nom du fichier et le mode qui peut valloir :

  • "r" pour ouvrir un fichier en lecture (valeur par défaut).
  • "w" pour ouvrir un fichier en écriture : crée le fichier s'il n'existe pas et écrit en écrasant l'existant.
  • "a" pour ouvrir un fichier en écriture en mode "append" : crée le fichier s'il n'existe pas et écrit à la fin du fichier (n'écrase pas l'existant).

En outre, vous pouvez préciser si le fichier doit être traité en mode texte ("t" - valeur par défaut) ou binaire ("b").

Vous pouvez alors utiliser les méthodes suivantes :

  • En lecture [après par exemple f = open("nomfichier.txt", "rt") ou f = open("nomfichier.txt") comme "r" et "t" sont choisis par défaut.
    • f.read() retourne une chaîne contenant toutes les lignes du fichier.
    • f.readlines() retourne une liste contenant toutes les lignes du fichier.
    • f.readline() retourne une chaîne contenant une ligne du fichier (le 1er appel affiche la 1ere ligne, le 2e appel la 2e ligne, etc.).
    • f.close() ferme le fichier (C'est une bonne pratique de toujours fermer le fichier lorsque vous avez terminé).
  • En écriture [après par exemple f = open("nomfichier.txt", "w") comme "t" est choisi par défaut]
    • f.write("Ceci est un texte") pour écrire une chaîne dans le fichier.
    • f.writelines(liste) pour écrire les éléments d'une liste dans le fichier.
    • f.close() ferme le fichier (C'est une bonne pratique de toujours fermer le fichier lorsque vous avez terminé).

Vous pouvez supprimer un fichier en utilisant le module os et la méthode remove comme ceci :

import os
os.remove("nomfichier.txt")
(au cas où : os pour operating system - système d'exploitation en français)

Enfin vous pouvez parcourir ligne par ligne un fichier avec un for comme ceci :

f = open("nomfichier.txt")
for ligne in f:
  print(ligne) #ligne est une chaîne

"\n" est le caractère retour à la ligne.

Chez Hercule & co, on souhaite sauvegarder dans un fichier ventes.txt toutes les ventes journalières. Chaque vente d'une journée est toujours sauvegardée dans une liste comme décrit précédemment.

On voudrait maintenant être capable chez Hercule & co de faire une synthèse sur les ventes.

Une fois le fichier ouvert en lecture, f.readlines() retourne une liste contenant toutes les lignes du fichier.

Testez dans le shell Python 3 (son grand intérêt est justement de pouvoir tester rapidement quelques instructions) :

>>> f=open("ventes.txt")
>>> f.readlines()
>>> f.readlines()

Il faut donc faire attention au fait que f.readlines() retourne une liste contenant toutes les lignes du fichier au premier appel, et si vous rappelez une deuxième fois f.readlines() vous aurez une liste vide. Il faut donc sauvegarder le résultat de f.readlines() dans une variable pour s'en servir plusieurs fois dans un programme.

Testez maintenant dans le shell Python 3 :

>>> f=open("ventes.txt")
>>> len(f.readlines())

Le nombre d'éléments de cette liste est le nombre de ligne du fichier qui correspond au nombre de jours de ventes dans le fichier. Aussi votre programme herculeventes.py peut commencer par :

f=open("ventes.txt")
ventes=f.readlines() 
print("Le fichier de ventes comporte",len(ventes),"jours de ventes.")

Testez ce programme faisant une première partie du travail à faire.

Il existe de nombreuses manières de réaliser un tel programme, on vous propose dans la suite une version utilisant uniquement des concepts "de base de la programmation" ainsi qu'une démarche de recherche de la solution.

Testez dans le shell Python 3 :

>>> f=open("ventes.txt")
>>> ventes=f.readlines()
>>> ventes[0]
'[[1, 2, 3], [2, 0, 1], [0, 0, 1]]\n'
>>> ventes[1]
'[[2, 2, 0]]\n'
>>> ventes[2]
'[[1, 2, 0], [12, 23, 24]]\n'

Avec le fichier de ventes donné en exemple, on a 3 éléments à la liste ventes (les 3 lignes du fichier). Les trois lignes ventes[0], ventes[1] et ventes[2] sont des chaînes de caractères. Il va falloir voir comment aller chercher les valeurs numériques. Pour ce faire, dans les méthodes de manipulation de chaînes de caractères (cf https://www.w3schools.com/python/python_strings.asp) il existe une méthode replace permettant de remplacer chaque occurences d'une chaîne par une autre :

Testez dans le shell Python 3 :

>>> "toto".replace("o","a") 
>>> "toto".replace("o","") 

La première instruction ci-dessus retourne "tata" car les "o" sont remplacés par des "a", alors que la deuxième retourne "tt" car les "o" sont remplacés cette fois par des chaînes vides "", autrement dit les "o" sont enlevés.

Pour récupérer les valeurs numériques présentent dans les chaînes ventes[i] i allant de 0 à len(ventes), il suffit donc d'enlever tous les caractères qui ne sont pas des nombres :

  • On va donc enlever les caractères "[[", "[", "]", "]]", "," et "\n".
  • Testez alors dans le shell Python 3 :
  • >>> ventes[0].replace("[[","")
    >>> ventes[0].replace("[[","").replace("[","")
    >>> ventes[0].replace("[[","").replace("[","").replace("]","")
    >>> ventes[0].replace("[[","").replace("[","").replace("]","").replace("]]","")
  • Puis continuez en enlevant les virgules "," et le caractère retour à la ligne"\n").
  • Comme l'expression commence à être longue, on va mettre ce résultat dans une variable s ainsi :
  • >>> s=ventes[0].replace("[[","").replace("[","")
    >>> s=s.replace("]","").replace("]]","")
    >>> s=s.replace(",","").replace("\n","")
    >>> s
    '1 2 3 2 0 1 0 0 1'
  • s ne contient donc plus que des nombres séparés par des espaces, ce qui va nous guider dans le choix d'une méthode pour récupérer les nombres : nous allons utiliser une autre méthode très pratique pour "découper" les chaînes qui est la méthode split. Cette méthode découpe une chaîne selon une chaîne séparatrice mise en paramètre de la méthode, et retourne tous les "bouts" dans une liste.
  • Testez dans le shell Python 3 :
  • >>> "toto".split("o")
    >>> "abc".split("b")
    >>> "a b c".split(" ")
    >>> "a b c".split()
    >>> "a,b,c".split(",")
  • L'espace (" ") est donc la chaîne séparatrice par défaut de la méthode split().
  • Tous les nombres (sous forme de chaînes) peuvent donc être récupérés dans une liste grâce à l'instruction s.split()
  • >>> s.split(" ")
    ['1', '2', '3', '2', '0', '1', '0', '0', '1']
  • Attention chaque élément est une chaîne, donc pour récupérer une valeur entière, il va falloir convertir chaque élément de la liste avec un int(element) pour s'en servir comme un entier.

Pour résoudre le problème, ce qui nous intéresse maintenant à chaque ligne, i.e. pour chaque jour, c'est :

  • le nombre de clients du jour
    • Il vaut le nombre d'éléments de liste divisé par 3.

    >>>l=s.split()
    >>>len(s.split(" "))//3
  • le nombre total de ventes du jour
    • Il vaut la somme des nombres de liste.

    >>> somme=0
    >>> for chaine in l:
    ...     somme = somme + int(chaine) # n'oubliez pas 4 espaces pour l'indentation
    ...     # on appuie directement sur entrée pour finir le for
    >>> somme
    10

    En bonus, on peut faire cela en une ligne en Python grâce à des expressions qui sortent du cadre de ce module M1207 consacré uniquement aux bases. Juste pour info donc mais pour vous montrer pourquoi Python est populaire et intéressant pour des scripts "visuellement épurés" :

    >>> sum(int(chaine) for chaine in l)
    10
  • le total du nombre d'H3 vendus du jour.
    • C'est la somme des nombres s'ils existent d'indice 0, 3, 6, ...
    • C'est-à-dire d'indice i tel que i est divisible par 3 (i%3==0).
  • le total du nombre d'A8 vendus du jour.
    • C'est la somme des nombres s'ils existent d'indice 1, 4, 7, ...
    • C'est-à-dire d'indice i tel que le reste de la division de i par 3 vaut 1 (i%3==1).
  • le total du nombre d'H2 vendus du jour.
    • C'est la somme des nombres s'ils existent d'indice 2, 5, 8, ...
    • C'est-à-dire d'indice i tel que le reste de la division de i par 3 vaut 2 (i%3==2).

Vous pouvez réaliser maintenant votre programme.

Vous aurez besoin de 5 variables supplémentaires :

  • 3 variables entières pour stocker les totaux de ventes pour chaque article (h3, a8, h2)
  • 1 liste pour stocker le nombre de clients pour chaque jour.
  • 1 liste pour stocker le nombre de de ventes pour chaque jour.

Il faudra alors ensuite remplir correctement ces variables en parcourant jour à par jour la liste ventes (comme dit plus haut parcourir une à une les chaînes ventes[i] pour i allant de 0 à len(ventes). Puis vous pourez afficher les résultats.

f=open("ventes.txt") 
ventes=f.readlines()
print("Le fichier ventes comporte",len(ventes),"jours de ventes.")
h3=0 # Total de ventes d'H3 
a8=0 # Total de ventes d'A8 
h2=0 # Total de ventes d'H2
nbclients=[] # Nombre de clients pour chaque jour
nbventes=[]  # Nombre de ventes pour chaque jour 

for i in range(0,len(ventes)):
	# ventes[i] = ventes du jour i+1
	
	# PARTIE À COMPLÉTER dans le for

	# Obtenir l la liste contenant les valeurs numériques des ventes (sous forme de chaînes)
	# Comme sur vos tests dans le shell python3

	# Une fois l obtenues 
	# Ajouter à nbclients le ombre de clients pour ce jour
	# Parcourir la liste élément par élément
	# for j in range(0,len(l)): 
	#     pour calculer h3, a8, h2 et le nombre total d'articles 
	#     vendus ce jour (pour l'ajouter après ce for à nbventes) 

print("Voici le nombre de clients par jour :",nbclients)
print("Voici le nombre total de ventes par jour :",nbventes)
print("Total de ventes d'H3 :",h3)
print("Total de ventes d'A8 :",a8)
print("Total de ventes d'H2 :",h2)

f=open("ventes.txt") 
ventes=f.readlines()
print("Le fichier ventes comporte",len(ventes),"jours de ventes.")
h3=0 # Total de ventes d'H3 
a8=0 # Total de ventes d'A8 
h2=0 # Total de ventes d'H2
nbclients=[] # Nombre de clients pour chaque jour
nbventes=[]  # Nombre de ventes pour chaque jour 

for i in range(0,len(ventes)):
	# ventes[i] = ventes du jour i+1
	s=ventes[i].replace("[[","").replace("[","")
	s=s.replace("]","").replace("]]","")
	s=s.replace(",","").replace("\n","")
	l=s.split() # liste contenant les valeurs numériques des ventes (sous forme de chaînes)
	nbclients.append(len(l)//3) # Nombre de clients pour ce jour i+1
	somme=0
	for j in range(0,len(l)):
		somme += int(l[j])
		if j%3==0:
			h3 += int(l[j])
		elif j%3==1:
			a8 += int(l[j])
		else:
			h2 += int(l[j])		 
	nbventes.append(somme) # Nombre d'articles vendus pour le jour i+1
print("Voici le nombre de clients par jour :",nbclients)
print("Voici le nombre total de ventes par jour :",nbventes)
print("Total de ventes d'H3 :",h3)
print("Total de ventes d'A8 :",a8)
print("Total de ventes d'H2 :",h2)

Exercices Python3 W3school

w3schools logo

Une fois tous les exercices finis, faire valider vos validations python quiz à faire par l'enseignant.

Finished! Hurrah! 🤟⚡️Si vous avez fini avant la fin, aidez les autres à finir aussi :-) N'oubliez pas de déposer l'archive de vos programmes et de faire votre mémento (écrire dans une note synthèse l'ensemble des mots clés importants à retenir pour écrire vos programmes).