Programmation impérative en Python Cours 5. Les listes et les tuples Olivier Baldellon à partir des notes, de Pierre Lezowski, Etienne Lozes et Jean-Paul Roy Courriel : pré[email protected]Page professionnelle : http://deptinfo.unice.fr/~obaldellon/ Université de Nice Sophia Antipolis (Université Côte d’Azur), Département d’Informatique
49
Embed
Programmation impérative en Python 3 — Cours 5. Les listes ...deptinfo.unice.fr/~obaldellon/pdf/baldellon-python-cours-05.pdf · Sommaire f Partiei.Annonces f Partieii.Séquences
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Programmation impérative en PythonCours 5. Les listes et les tuples
Olivier Baldellon à partir des notes, de Pierre Lezowski, Etienne Lozes et Jean-Paul Roy
Ï Il y aura un QCM la semaine prochaine (semaine de 09/03)Ï il sera notéÏ il se fera en fin de TPÏ il sera sur les chapitres 1 à 3
Ï Vérifiez votre groupe sur MoodleÏ Il faut venir au créneau de votre groupeÏ Sinon vous ne pourrez pas passer le QCM : 0/20Ï En cas de problème, me contacter par mail.
2/47
Examen de mi-semestre Partie i. Annonces
Ï Examen le mercredi 18 mars de 17h30 à 19h30Ï Sur les chapitres 1 à 5Ï On vous tiendra au courant du lieu
Ï En cas d’incompatibilité avec une autre UE.Ï Débrouillez-vous avec l’autre enseignant :)Ï Me contacter par mail
Ï Il n’y aura pas de cours de python la semaine du 16 Mars.Ï :’(Ï Ni CM, ni TP, ni TD
3/47
Sommaire
f Partie i. Annonces
f Partie ii. Séquences
f Partie iii. Accès et constructeur
f Partie iv. Mutabilité des listes
f Partie v. Gestion de la mémoire
f Partie vi. Petit algorithmes
f Partie vii. Table des matières
4/47
Définitions Partie ii. Séquences
Ï Une séquence est une suite finie de valeurs indexées.Ï On connaît déjà le type str (chaîne de caractères)Ï Il y a aussi les tuples et le listes.
>>> t = (1,2,3)>>> type(t)<class 'tuple'>>>> l = [1,2,3]>>> type(l)<class 'list'>
shell
Ï Une séquence peut contenir des éléments de types distincts :
>>> t = (2.0 , 'Salut', math.sqrt)# tuple de 3 éléments>>> [1, 'B', t , [3,4,5]] # liste de 4 éléments[1, 'B', (2.0, 'Salut', <built-in function sqrt>), [3, 4, 5]]
shell
5/47
Tuples Partie ii. Séquences
Ï Les tuples sont une généralisations des couples.Ï couple, triplet (3-uplet), quadruplet (ou 4-uplet), …, n-uplet
Une fonction ne peut retournerqu’une valeur,
mais peut retourner un tuple.
def division(a,b):q = 0r = awhile r >= b:
r = r - bq = q + 1
# q=a//b et r=a%breturn (q, r)
script
>>> t = division(37,7)>>> t # 37 = 5*7 + 2(5, 2)>>> t + (3,4) # concaténation(5, 2, 3, 4)>>> t[0]=17 # les tuples ne sont pas modifiablesTraceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
shell
6/47
Listes Partie ii. Séquences
Ï Les listes sont une généralisations des tuples.
Ï Exemple :Ï On souhaite conserver les prénoms des membres d’un clubÏ On peut utiliser les listes pour les stocker.
>>> club = ['Alice', 'Bianca', 'Carlos', 'Dagobert']>>> club = club + ['Etienne', 'Fatou']>>> club['Alice', 'Bianca', 'Carlos', 'Dagobert', 'Etienne', 'Fatou']
shell
Ï Zut alors ! On a oublié l’accent sur Étienne ! ! !
Ï Construction en extensionÏ tuples : les éléments entre parenthèses séparés par des virgulesÏ liste : les éléments entre crochets séparés par des virgules
Nombre d’éléments 0 1 cas général (ici 5 éléments)Tuple () (2,) (3,4,1,(1,3),-6)Liste [] [2] [3,4,1,(1,3),-6]
Chaîne '' '@' 'Salut'
Ï Un 1-uplet est possible mais peu utile : attention à la syntaxe (2,).
Ï La fonction len(S) donne la longueur (nombre d’éléments de S)
>>> len('')0>>> len((2,))1>>> len([0,1,2])3
shell
9/47
Opérations sur les séquences Partie iii. Accès et constructeur
Ï On peut concaténer deux séquences avec l’opérateur +
Ï Les opérations sont communes à ces trois types de séquence.
10/47
Accès par indice Partie iii. Accès et constructeur
Ï L’accès est commun aux chaines, tuples et listes.
>>> c = 'Saluton !'>>> c[0] # Premier'S'>>> c[len(c)-1] # Dernier'!'>>> t = (1,True,'profond')>>> len(t)3>>> t[1]True
shell >>> len(l)3>>> l[0] #Mon 1er est un chiffre6>>> l[1] #Mon 2nd est un booléeanTrue>>> l[2] #Mon 3ème est une chaîne'Yeux'>>> l #Mon tout est orange[6, True, 'Yeux']
shell
Ï Comme pour les chaînes, on peut utiliser des indices négatifs.
>>> l[-1] , t[-2] , c[-3] # Sans parenthèses('Yeux', True, 'n')>>> t[666] # Horreur, une erreurTraceback (most recent call last):File "<stdin>", line 1, in <module>
IndexError: tuple index out of range
shell
11/47
Parcours Partie iii. Accès et constructeur
Ï Pour parcourir une séquence, on peut utiliser des boucles.Ï en itérant sur les indices de 0 à len(Seq)-1Ï en itérant directement sur les éléments de la séquence.
def affiche(Seq):n=len(Seq)for i in range(n):
print(Seq[i],end=' -> ')print('')
scriptdef affiche(Seq):
for e in Seq:print(e,end=' -> ')
print('')
script
>>> affiche(c)S -> a -> l -> u -> t -> o -> n -> -> ! ->>>> affiche(t)1 -> True -> profond ->>>> affiche(l)6 -> True -> Yeux ->
shell
Ï C’est le même programme pour les trois types de séquences !
12/47
Écrire une fonction index Partie iii. Accès et constructeur
Ï On souhaite connaître l’indice d’un élément d’une séquenceÏ On retourne le premier indice qui convientÏ Si aucun indice ne couvient, on renvoie -1
def index(Seq,x):for i in range(len(Seq)):
if Seq[i]==x:return i
# On sort de la boucle si on a pas trouvé xreturn -1
La méthode index Partie iii. Accès et constructeur
Ï Une méthode similaire existe déjà.Ï Mais il faut savoir l’écrire soit même!
>>> liste = [4, -2, False, 'Coucou',-2, (3,5)]>>> liste.index('Coucou')3
shell
Ï En cas de plusieurs index valides, c’est le premier qui est renvoyé.Ï On peut donner un indice de départÏ Si aucun n’est valide, le programme se termine par un erreur.
>>> liste.index(-2)1>>> liste.index(-2,2) # on cherche à partir de liste[2]4>>> liste.index(5)Traceback (most recent call last):File "<stdin>", line 1, in <module>
ValueError: 5 is not in list>>> (10,20,30).index(30) # marche avec tuples et chaînes2>>> 'abcdef'.index('bcd') # marche avec des sous-chaînes1
shell
14/47
Déstructuration Partie iii. Accès et constructeur
Ï On peut déstructurer un tuple ou une liste.Ï nécessite de connaître la taille en écrivant le programme.Ï permet de définir plusieurs variables d’un coup
>>> liste=[1,2,3]>>> [a,b] = listeTraceback (most recent call last):File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
shell
15/47
Extraction de tranche Partie iii. Accès et constructeur
Ï Comme pour les chaînes, on peut extraire des tranches.Ï On accède à un élément d’une séquence avec la notation [i]Ï On accède à une suite d’élèments avec la notation [i,j]Ï On accède à une suite d’élèments avec la notation [i,j,p]
>>> c = 'Salut à toi'>>> l = ['Zéro','Un','Deux','Trois','Quatre','Cinq']>>> t = (0,1,2,3,4,5)
Ï On ne peut pas modifier les tuples et les chaînes
>>> s[3]='î'Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment>>> t[1]='u'Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
shell
Ï On peut cependant réaffecter une chaîne et un tuple
>>> s='Chaîne'>>> t=('t','u','p','l','e')
shell
22/47
Remarques sur la mémoire Partie iv. Mutabilité des listes
>>> c1 = 'Chaîne vachement très très longue'>>> c2=c1
shell
Ï La chaine 'Chaîne … longue' est stockée une fois en mémoire.Ï On dit que c1 et c2 pointe vers la même chaîne de caractère.Ï l’affection c2=c1 est instantané.
Ï Démonstration avec une séquence mutable (une liste donc)
Ajout d’un élément Partie iv. Mutabilité des listes
>>> l = [0,1,2]>>> l = l + [3]>>> l[0, 1, 2, 3]
shell >>> l = [0,1,2]>>> l.append(3)>>> l[0, 1, 2, 3]
shell
Ï Le premier programmeÏ recrée une liste similaire à l (peut-être long si l est grand)Ï ajoute 3 à la fin de la nouvelle liste.
Ï La méthode appendÏ modifie la liste l directement.
>>> l1=[0,1,2] ; l2=[0,1,2]>>> m1=l1 # La liste n'est pas recopiée>>> m2=l2 # La liste n'est pas recopiée>>> l1=l1+[3] # On crée une nouvelle liste>>> print(l1,m1)[0, 1, 2, 3] [0, 1, 2]>>> l2.append(3) # on modifie la liste>>> print(l2,m2)[0, 1, 2, 3] [0, 1, 2, 3]
shell
24/47
Exemple : créer la liste des diviseurs Partie iv. Mutabilité des listes
Ï La fonction diviseurs(n) va retourner la liste des diviseurs de n.Ï uniquement ceux non triviaux (distincts de 1 et n)Ï on impose à n d’être un entier strictement positif.
Ï Liste ou tuple?Ï On peut efficacement ajouter des éléménts à une liste : appendÏ Il n’y a pas d’équivalent pour les tuples (immutable/immuable)Ï On ne connaît pas à l’avance le nombre d’éléments du résultatÏ On va donc utiliser une liste plutôt qu’un tuple
list.append(x) Ajoute un élément à la fin de la liste.list.extend(x) Étend la liste en y ajoutant tous les éléments de l’itérable.list.insert(i,x) Insère un élément à la position indiquée. Le premier argument est la
position de l’élément courant avant lequel l’insertion doit s’effectuer.list.remove(x) Supprime de la liste le premier élément dont la valeur est égale à x.
Erreur s’il n’existe aucun élément avec cette valeur.list.pop(i) Enlève de la liste l’élément situé à la position indiquée et le renvoie en
valeur de retour. Si aucune position n’est spécifiée, a.pop() enlève etrenvoie le dernier élément de la liste.
list.index(x) Renvoie la position du premier élément de la liste dont la valeur égalex. Erreur si aucun élément n’est trouvé.
list.count(x) Renvoie le nombre d’éléments ayant la valeur x dans la liste.list.sort() Ordonne les éléments dans la liste, en place.list.reverse() Inverse l’ordre des éléments dans la liste, en place.
Ï La mémoire d’un programme comporte deux zones distinctes :Ï la pile, qui contient les variables locales,Ï le tas, qui contient les variables globales et les objets (séquences,
La pile et les variables locales Partie v. Gestion de la mémoire
Ï Chaque appel de fonction crée un pile locale.Ï Cette pile et les variables associées disparaissent à la fin de la fonction.Ï La durée de vie de ces variables est celle de l’appel.
def f(x):y = 1 # ¬g(y) # print(x) # ®
def g(y):x = y
f(3) # affiche 3
script
Ï Chaque appel de fonction à son propre espace de nom.Ï Le x de f n’est pas le même que celui de gÏ Cela permet de ne pas s’embrouiller
Ï Si on appelle plusieurs fois une fonction, il y aura une pile par appel.
29/47
La pile et les appels de fonctions Partie v. Gestion de la mémoire
Ï La durée de vie d’une variable globale est celle du programme.Ï Sa portée s’arrête aux définitions des fonctions.Ï Dans une fonction, une variable que l’on modifie est implicitement
locale, même si une variable globale porte le même nom.
x = 0x = x + 1 # ¬
def f(y):x = y #
f(2) # ®print(x) # affiche 1
script
30/47
Le tas et les variables globales Partie v. Gestion de la mémoire
Ï On veut faire modifier une variable globale par une fonction.
Ï Comment étendre sa portée à la définition de fonction?
Ï En ajoutant le mot-clé global.
x = 0x = x + 1 # ¬
def f(y):global xx = y #
f(2) # ®print(x) # affiche 1
script
Ï global est seulement requis pour modifier une variable globale.
Ï Cependant, le code est plus clair en le précisant toujours.
31/47
Partage de variables Partie v. Gestion de la mémoire
Ï Rappel : dans Processing, on avait déjà vu le mot-clé global pourpartager l’état du monde entre les différentes fonctions.
Ï En Processing, les fonctions setup() et draw() sont appeléesautomatiquement.
32/47
Listes et variables Partie v. Gestion de la mémoire
Ï Lors de l’affectation L=[1,2,3] :Ï la variable L contient un lien (un pointeur) vers la liste [1,2,3])Ï le pointeur de L est dans la pileÏ le contenu [1,2,3] est dans le tas
Ï Plusieurs variables peuvent pointer vers la même liste !
>>> L = [1, 2, 3]>>> M = L # ¬ M et L pointent vers la même liste>>> M[0] = 4 # modification indirecte de L[0]>>> L[4, 2, 3]
shell
33/47
Être ou ne pas être égal… Partie v. Gestion de la mémoire
Ï Que signifie L et M sont la même liste ?
Ï À ne pas confondre :Ï L’égalité testée avec == : les listes ont le même contenu.Ï L’identité testée avec is : les listes pointent au même endroit mémoire.
>>> L = [1,2,3] ; N = [1,2,3]>>> M = L>>> print(M is L , M==L) # M et L sont identiquesTrue True>>> print(M is N , M==N) # Égales mais non identiquesFalse True
shell
Ï Exercice : écrire une fonction copy(L) qui retourne un liste égale maisdistincte de L.
34/47
Append et affectation Partie v. Gestion de la mémoire
>>> L = [1,2]>>> M = L ; affiche()L:[1, 2] M:[1, 2] L is M:True>>> L.append(3) ; affiche()L:[1, 2, 3] M:[1, 2, 3] L is M:True>>> L = L + [4] ; affiche()L:[1, 2, 3, 4] M:[1, 2, 3] L is M:False
shell
Ï Le calcul de L+[4] créé une nouvelle listeÏ Peut être très long si L est grandÏ Crée un nouvel objet en mémoire
Ï L’appel de L.append(3) prolonge la listeÏ est très rapideÏ a un effet globale !
35/47
Listes et appels de fonction Partie v. Gestion de la mémoire
Ï Attention : le contenu d’une liste est toujours modifiable globalement.Ï La variable L contient un lien vers la liste [1,2,3]Ï Ce lien n’est pas modifiable (par défaut) par un fonction (variable locale).Ï Le contenu pointé par le lien est toujours modifiable.
Ï Pas de global M dans la fonction fÏ Donc M n’est pas modifié (pointe
toujours vers la même liste)Ï Mais le contenu de cette liste a changé !
36/47
Sommaire
f Partie i. Annonces
f Partie ii. Séquences
f Partie iii. Accès et constructeur
f Partie iv. Mutabilité des listes
f Partie v. Gestion de la mémoire
f Partie vi. Petit algorithmes
f Partie vii. Table des matières
37/47
Chiffres dans une chaîne Partie vi. Petit algorithmes
Ï Calculons la liste des chiffres d’une chaîne s.Ï Nous utilisons la méthode isdigit() de la classe str.Ï Vous devez être capable d’écrire isdigit ! (cf. TP 3)
Chiffres dans une chaîne avec compréhension Partie vi. Petit algorithmes
Ï Méthode Pythonesque : compréhension de liste.
def chiffres(s):return [c for c in s if c.isdigit()]
script
Ï Notez l’ordre des instructions :Ï D’abord le for puis le ifÏ Comme dans le programme précèdent.
Ï Ne marche pas (forcément) avec les autres langages.
Ï Durant cette UE privilégiez la méthode classique.
39/47
Plus petit diviseur Partie vi. Petit algorithmes
Ï Principes : (Déjà vu dans un cours précédent : Cours 2)Ï on traite les nombres pairs (divisibles par 2) à part,Ï d divise n si et seulement si n%d == 0,Ï n non premier admet nécessairement un diviseur d≤p
n
def ppdiv(n):if n%2==0:
return 2racine = int(sqrt(n))for d in range(3,racine+1,2):
if n%d==0:return d
return n
script
>>> ppdiv(2003) # premier2003>>> ppdiv(1003) # non premier17>>> [(c,ppdiv(c)) for c in range(15,20)][(15, 3), (16, 2), (17, 17), (18, 2), (19, 19)]
shell
40/47
Liste des nombres premiers Partie vi. Petit algorithmes
Ï Il est facile de tester si un nombre est premier en utilisant ppdiv…
def estPremier(n):if n<2:
return Falseelse:
return ppdiv(n)==n
script
Ï … puis de construire la liste des nombres premiers jusqu’à n :
Ï Exercice : écrire cette fonction en une ligne (par compréhension)
41/47
Tri d’une liste par ordre croissant Partie vi. Petit algorithmes
Ï Python possède deux primitives pour trier une liste L de nombres.Ï la fonction sorted(L) qui construit une nouvelle copie de LÏ La méthode L.sort() qui trie la liste L en place (sans créer de nouvelle
Tri : Temps de calcul Partie vi. Petit algorithmes
Ï Le temps de calcul de cet algorithme pour trier une liste à n éléments estproportionnel à n · log(n). Petite expérience :
from time import timefrom random import randint
def chrono(n):# On crée une liste de n nombres aléatoiresL = [randint(1,1000) for i in range(n)]t = time() # On lance le chronoL.sort() # On fait le trit = time() - t # On arrête le chronoprint('Temps pour',n,':',int(t*1000),'ms')
script
>>> chrono(200000)Temps pour 200000 24 ms>>> chrono(400000)Temps pour 400000 51 ms
shell
Ï En doublant n, on fait un peu plus que doubler le temps de calculÏ ce qui est cohérent avec « n · log(n) »
43/47
Tri par sélection — Qu’est-ce? Partie vi. Petit algorithmes
Ï Il existe de nombreux algorithmes de tri.Ï Quicksort, tri rapide, fusion, par tas, du sleep, etc.Ï les meilleurs sont en n · log(n)Ï La tri par séléction est proportionnelle à n2
m = imin(L,i) # minimum de la fin de liste(L[i], L[m]) = (L[m], L[i]) # échangeprint('L=', L) # pour espionner la boucle
script
Ï À la fin de chaque étape les i premiers éléments sont triés.
Ï Par super efficace, mais ça marche!
45/47
Tri par sélection — L’humiliation Partie vi. Petit algorithmes
def chrono2(f,n):# On crée une liste de n nombres aléatoiresL = [randint(1,1000) for i in range(n)]t = time() ; f(L) ; t = time() - tprint(f.__name__,':',int(t*1000),'ms')