Les conteneurs en Python¶
Notions globales¶
On appelle conteneur (container) un objet ayant vocation à en contenir d’autres
Il existe plusieurs types de conteneurs :
liste
dictionnaire
ensemble
n-uplet
Dans un certaine mesure, on peut aussi considérer les chaînes de caractères comme des conteneurs
Voici quelque exemples :
s = "Bonjour" # chaîne de caractère
l = [1, 2, "bonjour", [1, 2]] # liste
d = {'key1':123.45, 3:"bonjour"} # Dictionnaire
e = {1, 2, 4} # ensemble
t = (1, 2, [1, 2]) # n-uplet / tuple
L’opérateur in¶
Il permet de tester si un le conteneur contient un objet donné.
print(1 in l)
print(3 in d) # Pour les dictionnaires, c'est la clé
print('on' in s) # Pour les chaînes de caratères, n'importe quelle sous-chaîne
True
True
True
Longueur¶
Un autre point commun partagé par de nombreux conteneurs est qu’ils possèdent une taille. C’est-à-dire qu’ils contiennent un nombre fini et connu d’éléments, et peuvent être passés en paramètre à la fonction len.
print(len(t))
3
Objet subscriptables¶
Cela désigne les objets sur lesquels l’opérateur [] peut être utilisé. L’ensemble des types cités sont subscriptables, à l’exception de l’ensemble (set), qui n’implémente pas l’opération []
Parmis les objets subscriptables, on distingues ceux qui sont indexables par un entier et ceux qui sont sliceables.
Les dictionnaires ne sont pas indexables. Les liste et les chaînes de caractères sont indexable et sliceables.
print(d["key1"])
print(l[2])
print(s[1])
123.45
bonjour
o
Pour les objets indexables, on rappel que le premier élément est l’élément 0. Le dernier est dont n-1 ou n est la taille de l’objet.
Les slices permettent de récupérer une partie de l’objet initial.
La syntaxe est [start:stop:step]
. Si on omet step, alors le pas est de 1. Si on omet stop, alors il s’agit de n, si on omet start, il s’agit de 0.
La taille de l’objet renvoyé est (stop - start)//step .
ATTENTION : si on indexe avec [i:j], alors le dernier élément est j-1
print(s[1:4])
print(l[1:2])
print(s[::2])
onj
[2]
Bnor
Les indices négatifs, sont pris modulo la taille du conteneur.
print(l[:-1]) # Tous les éléments sauf le dernier
Conteneurs modifiables¶
Les listes, les dictionnaires et les ensembles sont modifiables. Les n-uplet et les chaines de caratères ne le sont pas.
Par modifiable, on entent par exemple que l’on peut rajouter, suprimer ou remplacer un élément.
liste1 = ['Bonjour']
liste1.append('Hello')
liste1.insert(1, 'Salut')
del liste1[0]
liste1[1] = 'Coucou'
liste1
['Salut', 'Coucou']
Une liste, c’est comme un classeur, on peut rajouter ou suprimer des feuilles. Ce sera toujours le même classeur. Un objet non modifiable ne possède par la méthode append, insert. On ne peut pas faire objet[i] = qqc. C’est comme un livre, il n’est pas possible de le modifier. La seule chose que l’on peut faire, c’est imprimer un nouveau livre avec une modification.
Si vous acheter deux livres identiques, il seront toujours identiques. Si vous achetez deux classeurs identiques, leur contenu pourra être différent.
En Python, la plupart des objets sont modifiables. Les exceptions sont les nombres, les n-uplets et les chaines de caractères.
Attention : lorsque l’on passe un objet à une fonction, il n’est pas dupliqué. Si la fonction modifie l’objet, alors l’objet est modifié.
# Dans cet exemple, il n'y a qu'une seule liste
def f(c):
c.append(3)
a = [1, 2]
b = a
f(b)
print(a)
[1, 2, 3]
Conteneurs iterables¶
C’est le cas des conteneurs que l’on peut utiliser dans un boucle for. Tous les conteneurs ci dessus sont iterables. Dans la mesure du possible, il est important de faire la boucle for directement sur l’objet, plutôt que par exemple sur ses indices.
for lettre in s:
print(lettre)
for item in l:
print(item)
B
o
n
j
o
u
r
1
2
bonjour
[1, 2]
Pour les dictionnaires, il est possible d’itérer sur les clés, les valeurs, ou les deux:
for key in d: # On peut utiliser d.keys()
print(key)
for val in d.values():
print(val)
for key, val in d.items():
print(key, val)
key1
3
123.45
bonjour
key1 123.45
3 bonjour
Si on souhaite parcourir une liste et avoir l’indice, il est possible d’utiliser la fonction enumerate:
for i, item in enumerate(l):
print(f"L'item numero {i} est {item}")
L'item numero 0 est 1
L'item numero 1 est 2
L'item numero 2 est bonjour
L'item numero 3 est [1, 2]
Si on souhaite parcourir deux listes en même temps, on peut utiliser la fonction zip
liste1 = ['A', 'B', 'C']
liste2 = [10, 4, 24]
for lettre, nombre in zip(liste1, liste2):
print(lettre, nombre)
A 10
B 4
C 24
List comprehension¶
Il arrive fréquement que l’on souhaite créer un conteneur à partir d’un autre. Par exemple, on a une liste et on souhaite appliquer une fonction sur tous les élements. On souhaite filter un dictionnaire, …
Un façon simple consiste à créer un conteneur vide et ensuite le remplir au fur et à mesure :
ancienne_liste = [1, 4, 6, 3]
nouvelle_liste = []
for val in ancienne_liste:
nouvelle_liste.append(val/2)
La technique de list comprehension permet de le faire en une seule ligne
nouvelle_liset = [val**2 for val in ancienne_liste]
Cette methode fonctionne aussi pour les dictionnaires ou les ensembles
liste2 = ["bonjour", "hello"]
print({val:i for i, val in enumerate(liste2)})
{i**2 for i in range(-5, 5)}
{'bonjour': 0, 'hello': 1}
{0, 1, 4, 9, 16, 25}
Il est possible en plus de filtrer une liste
[i for i in range(20) if i%2==0 and i%3!=1]
[0, 2, 6, 8, 12, 14, 18]
Les différents types de conteneurs¶
Les listes¶
Pour créer une liste, on utiliser les []. Il est aussi possible de créer une liste à partir d’un objet itérable.
l = [1, 2]
l = list('Bonjour')
['B', 'o', 'n', 'j', 'o', 'u', 'r']
Voici quelques méthodes et fonctions :
append : rajoute un élément à la fin
insert : rajoute un élément à la position i
extend : étend la liste en rajoutant les éléments d’un autre liste
l1 + l2 : crée une nouvelle liste en concaténant les deux listes.
sort : modifie la liste en la triant (la fonction sorted renvoie une nouvelle liste)
index : trouve l’indice d’un élément (ou renvoie une ValueError si il n’existe pas)
count : compte le nombre d’élément ayant la valeur donnée en argument
pop : suprime et renvoie le dernier élément
Les dictionnaires¶
Pour créer un dictionnaire :
# ces trois dictionnaires sont identiques
d = {'key1':'Bonjour', 'key2':'Hello'}
d = dict(key1="Bonjour", key2="Hello")
l = [('key1', 'Bonjour'), ('key2', 'Hello')]
d = dict(l)
Quelques méthodes:
keys, values, items : renvoie une ‘liste’ (en fait ce n’est pas vraiment une liste) sur laquelle on peut faire une boucle for (voir ci-dessus)
get : récupère une clé, l’intérêt est la possibilité d’utiliser une valeur par défaut si la clé n’existe pas
setdefault : défini une valeur si celle ci n’existe pas
update : modifie le dictionnaire à partir d’un nouveau dictionnaire. Il n’est pas possible de faire un ‘+’ ente deux dictionnaires
Remarques sur les clés : souvent les clés sont des chaînes de caractères, mais ce n’est pas obligatoire. On peut utiliser n’importe quel objet non modifiable ne contenant pas d’objet modifiable: nombre, chaine de caractère ou tuple contenant des objets non modifiables.
Les ensembles¶
Correspond à la notion mathématique. Il ne peuvent contenir deux objets identiques. Ils sont rarement utilisés, mais pratique lorsque l’on en a besoin. On peut aussi créer un ensemble à partir de n’importe quel objet itérable
s = {1, 5}
s = set(range(3))
Opérations sur les ensembles :
&
: intersection|
: union-
: difference^
: difference symétrique
s1 = {1, 2, 3, 4}
s2 = {2, 3, 4, 5}
print(s1 & s2)
print(s1 | s2)
print(s1 - s2)
print(s1 ^ s2)
{2, 3, 4}
{1, 2, 3, 4, 5}
{1}
{1, 5}
Les n-uplets¶
Similaires aux listes, il ne sont pas modofiables, ce qui permet de les utiliser comme clé dans un dictionnaires. Les n-uplets (tuple en anglais) sont aussi utilisé lorsqu’un fonction renvoie plusieurs éléments.
Il sont créé avec des (). Attention aux cas particulier du 1-uplet
t = ()
t = (1,) # (1) n'est pas un 1-uplet, mais juste le nombre 1
t = (1, 2, 56)
Seules les méthode count et index existent (et font la même chose que pour une liste).
Le +
permet la concaténation