1NSI : cours Ensembles Python⚓︎
Introduction⚓︎
Def
Un , ou un
, est un conteneur d'
- NON ORDONNÉS (en particulier : PAS d'indices)
- UNIQUES (donc PAS de doublons)
C'est une structure de données primitive de Python, qui est un type construit donc un conteneur/collection d'éléments.
Un ensemble / set
en Python, modélise la notion d'ensemble en Mathématiques.
Les types des éléments peuvent :
- être variables, pour certains langages, dits à typage dynamique (Python, ..),
- ou pas, pour certains autres langages, dits à typage statique (langage C, Java, etc..)
Définir un Ensemble avec des {}
⚓︎
On définit un ensemble de type set
, avec des accolades {}
# On peut mettre des nombres dans un ensemble
>>> s = {3,4,5}
# et même : un mélange de plusieurs types de nombres
>>> s = {3,4,5.2}
# voire : un mélange de nombres, et d'autres types
>>> s = {2,3,7,5.4,"Bonjour"}
>>> print(s)
{2, 3, 5.4, 'Bonjour', 7}
# Classiquement: on met des lettres
>>> s = {'a','b','j','m','n','o','r','u'}
# On ne prend PAS en compte les répétitions !
# ni l'ordre (alphabétique, ou croissant, etc..)
>>> s = {'a','b','c','a','b','a','b','c'}
>>> print(s)
{'b', 'a', 'c'}
Quels éléments peut contenir un ensemble ?
- Un ensemble peut contenir des éléments de type
int
,float
,str
,tuple
Plus généralement, un ensemble doit contenir des objets hashables (cf définition ci-très-en-dessous) : - Sont hashables, donc peuvent appartenir à un ensemble, les types :
int
,float
,str
,tuple
- Ne sont PAS hashables, donc ne peuvent PAS appartenir à un ensemble, les types :
list
,set
,dict
{}
ne désigne PAS l'ensemble vide (cette notation sera réservée pour le dictionnaire vide)
Remarque : Les ensembles / set
ne peuvent pas contenir des sous-ensembles / set
. Pour représenter des set
de set
les set
intérieurs doivent être des frozenset
.
Les frozenset
sont un type de données très semblable au type set
, mais qui a pour différence notable par rapport aux set
qu'ils sont immutable et hashables, il peut ainsi être utilisé comme clef de dictionnaire ou élément d'un autre set.
Définir un ensemble avec set()
⚓︎
Il est fréquent d'utiliser des caractères comme éléments d'un ensemble. Pour simplifier la définition de tels ensembles, on peut utiliser le constructeur de type set()
pour définir un ensemble sans répétition des caractères rencontrés:
>>> s = set("abracadabra")
>>> print(s)
{'r', 'c', 'd', 'a', 'b'}
# ATTENTION aux ESPACES, aux ACCENTS, à la CASSE, aux caractères inusuels, etc
>>> s = set("Bonjour mère, je vais bien")
>>> print(s)
{'r', ',', 'B', ' ', 'e', 'j', 's', 'b', 'è', 'n', 'm', 'a', 'u', 'v', 'o', 'i'}
Remarque : la notation set()
permet de définir l'ensemble vide
Plus généralement, on peut générer un ensemble grâce à set(iterable)
où iterable
est un itérable (chaînes, listes, tuples, dictionnaires, fichiers, etc..)
# une liste et/ou un tuple sont des itérables
>>> s = set([1,6,4,6,4,4])
>>> print(s)
{1,6,4}
>>> s = set((1,6,4,6,4,4))
>>> print(s)
{1,6,4}
Fonctions utiles sur les Ensembles⚓︎
Longueur d'un ensemble⚓︎
>>> s = set("abracadabra")
>>> print(s)
{'r', 'c', 'd', 'a', 'b'}
>>> len(s) # renvoie le nombre d'éléments/objets de l'ensemble
5
len
renvoie la longueur (/le cardinal en mathématiques) de l'ensemble s
Ensemble Vide⚓︎
# set() désigne l'ENSEMBLE VIDE
>>> s = set()
>>> len(s)
0 # la longueur de l'ensemble vide vaut 0
{}
représente le dictionnaire vide, mais PAS l'ensemble vide
Appartenance à un Ensemble avec in
, ou pas, avec not in
⚓︎
>>> s = set("abracadabra")
>>> s
{'r', 'c', 'd', 'a', 'b'}
>>> 'a' in s
True
>>> 'e' in s
False
>>> {'c','d'} in s
False
# ou bien NON appartenance avec les mots-clés `not in`
>>> 'a' not in s
False
# les ensembles ne peuvent PAS contenir de sous-ensembles
s = {'r', {'c', 'd'}, 'a', 'b'}
TypeError: unhashable type: 'set'
Indices / Index⚓︎
NOOOOON ! On a dit PAS d'indices (car pas d'ordre) sur les ensembles. donc PAS de tranches/slices non plus sur les ensembles.
Les Ensembles NE sont PAS des Séquences⚓︎
Les Ensembles disposent bien d'une fonction len()
, mais PAS d'indices entiers: en particulier ils ne sont pas ordonnés (contrairement aux séquences), donc :
Pte
Les ensembles set
NE sont PAS des séquences.
Techniques de parcours d'Ensembles⚓︎
Technique 1 : élément par élément, SANS indices⚓︎
s=set('abracadabra')
for element in s:
print(element)
Pte
Les ensembles set
sont des itérables.
Technique 2 : élément par élément, AVEC des indices⚓︎
Cette technique N'existe PAS : car pas d'indices...
Méthodes sur les Ensembles⚓︎
Méthodes usuelles sur les Ensembles⚓︎
Notons s1
et s2
deux ensembles.
s1={1,2}
et s2={2,4,6,8}
- Appartenance :
x in s1
renvoieTrue
si l'élémentx
appartient à l'ensemble, ouFalse
sinon.x not in s1
renvoieTrue
six
n'est PAS danss1
, etFalse
sinon
- Ajout d'éléments :
s1.add(x)
ajoute l'élémentx
à l'ensembles1
. Ex :s1.add(3)
ajoute3
à l'ensembles1
ATTENTION
(syntaxe mutable) : ne PAS écrire
s1 = s1.add(x)
qui écrase totalement la variables1
(après quoi :s1
vautNone
) Par contre, cette méthode ne permet d'ajouter qu'un seul élément à la fois. Pour ajouter plusieurs éléments à la fois :s1.union(iterable)
renvoie les éléments des1
auxquels on a ajouté tous les éléments de l'iterable
mais sans modifiers1
. Ex :s1.union({4,5})
renvoie{1,2,3,4,5}
Union \(\cup\) :s1 | s2 \(\quad\) ( symbole|
= AltrGr+6) renvoie l'union des1
ets2
, mais sans modifiers1
. renvoie les éléments de l'ensembles1
auxquels on a ajouté tous ceux de l'ensembles2
, mais sans modifiers1
Notation | =
:s1 | = s2
signifies1 = s1 | s2
s1.update(iterable)
ajoute tous les éléments de l'iterable
à l'ensembles1
. Ex :s1.update([6,7])
:s1
vaut{1,2,3,4,5,6,7}
- Suppression d'éléments :
s1.remove(x)
supprime l'élément existantx
de l'ensembles1
ATTENTION
: lève une exception
KeyError
si l'élémentx
est inexistant dans l'ensembles1
: Ex :s1.remove(10)
renvoieKeyError: 10
s1.discard(x)
supprime l'élémentx
de l'ensembles1
six
appartient às1
, mais ne lève pas d'erreur en cas d'inexistance dex
danss1
. Ex :s1.discard(10)
supprime10
des1
lorsque c'est possible (si10
appartient às1
, sinon ne fait rien)s1.pop()
retire et renvoie un élément arbitraire/aléatoire de l'ensembles1
.ATTENTION
: Lève une exception
KeyError
si l'ensemble est vide.s1.clear()
supprime tous les éléments duset
- Différence/Soustraction d'ensembles:
- Différence avec un itérable:
s1.difference(iterable)
renvoie la soustraction / différence des1
par l'iterable
, c'est-à-dire les éléments des1
qui ne sont PAS dansiterable
, mais sans modifiers1
. Différence \(-\) :s1 - s2 \(\,\) renvoie la différence des1
pars2
, mais sans modifiers1
. Ex :{1,2,3,4,5,6,7} - {2,4,6,8} = {1,3,5,7}
Notation -=
:s1 -= s2
signifies1 = s1 - s2
- Différence Symétrique avec un itérable :
s1.symmetric_difference(iterable)
renvoie la différence symétrique des1
pariterable
, c'est-à-dire les éléments qui sont :- soit dans
s1
, - soit dans
iterable
, - mais pas dans les deux simultanément.
- soit dans
Différence Symétrique \(\Delta\) :s1 ^ s2 \(\,\) ous1.__xor__(s2)
renvoie la différence symétrique des1
pars2
, mais sans modifiers1
. Ex :{2,3,4,5} ^ {2,3,8} = {4,5,8}
Notation ^=
:s1 ^= s2
signifies1 = s1 ^ s2
- Différence avec un itérable:
- Duplication :
s2 = s1.copy()
copie l'ensembles1
danss2
- Intersections :
- Intersection avec un itérable :
s1.intersection(iterable)
- renvoie l'intersection de
s1
aveciterable
, c'est-à-dire les éléments des1
qui appartiennent également àiterable
. - Remarque: renvoie
set()
lorsque l'intersection est vide.
- renvoie l'intersection de
Intersection \(\cap\) :s1 & s2 renvoie l'intersection entres1
ets2
, mais sans modifiers1
Ex :{2, 3, 4, 5} & {2,3,8}
renvoie{2,4}
Notation &=
:s1 &= s2
signifies1 = s1 & s2
s1.isdisjoint(iterable)
- renvoie
True
lorsque l'ensembles1
est disjoint deiterable
(pas d'élément en commun), ou False
sinon (au moins un élément commun)
- renvoie
- Intersection avec un itérable :
- Inclusions :
- Inclusion d'un itérable :
s2.issubset(iterable)
- renvoie
True
si l'ensembles2
est inclus ou égal àiterable
(/est un sous-ensemble de), - ou
False
sinon
- renvoie
Inclusion \(\subseteq\) :s2 < = s1 - renvoie
True
si l'ensembles2
est inclus ou égal à l'ensembles1
False
sinon
- renvoie
Inclusion stricte \(\subset\) :s2 < s1 - renvoie
True
si l'ensembles2
est strictement inclus dans l'ensembles1
False
sinon
- renvoie
- Contient un itérable :
s2.issuperset(iterable)
- renvoie
True
si l'ensembles2
contient ou est égal àiterable
(/est un sur-ensemble de), - ou
False
sinon
- renvoie
Contient \(\supseteq\) :s2 > = s1 - renvoie
True
si l'ensembles2
contient ou est égal à l'ensembles1
False
sinon
- renvoie
Contient strictement \(\supset\) :s2 > s1 - renvoie
True
si l'ensembles2
contient strictement l'ensembles1
False
sinon
- renvoie
- Inclusion d'un itérable :
Liste Complète des Méthodes sur les Ensembles⚓︎
Aide en ligne⚓︎
Vous trouverez une Liste Complète de Méthodes opérant sur les Ensembles, sur : * cette page de la Documentation Officielle * ou sur cette autre page de la Documentation Officielle
Aide en Local (dans un Interpréteur Python)⚓︎
-
Dans un interpréteur Python,
dir(set)
affiche la liste complète de toutes les méthodes disponibles sur lesset
, y compris les méthodes magiques/spéciales (cf ci-dessous), mais elles ne sont pas documentées (ni signature, ni docstring). -
Dans un interpréteur Python,
help(set)
affiche la liste complète de toutes les méthodes disponibles sur lesset
, y compris les méthodes magiques/spéciales (cf ci-dessous), AVEC DOCUMENTATION: AVEC LEURS SIGNATURES ET LES DOCSTRINGS.
Méthodes magiques / Méthodes spéciales sur les Ensembles⚓︎
Méthodes magiques / Méthodes spéciales sur les Ensembles
Parmi toutes les méthodes disponibles affichées par dir(set)
, certaines sont encadrées par deux underscores (de chaque côté) __unCertainNom__()
: Elles sont appelées des
- elles sont accessibles via la syntaxe normale pour les méthodes :
nomEnsemble.__nomMethodeMagique__()
- elles sont également accessibles via une syntaxe spéciale / magique (qui dépend de la méthode en question)
de Méthodes magiques / Méthodes spéciales sur les Ensembles
On se donne deux listes s1={1,2,3,4}
et s2={5,6,7}
__len()__
: calcule la longueur d'un ensemble ...- Syntaxe normale :
s2.__len__()
renvoie le nombre \(3\) - Syntaxe spéciale :
len(s2)
renvoie le nombre \(3\)
- Syntaxe normale :
__eq()__
: teste l'égalité entre deux ensembles ...- Syntaxe normale :
s1.__eq__(s2)
renvoieFalse
cars1
ets2
ne sont pas égaux - Syntaxe spéciale :
s1 == s2
renvoieFalse
(pour les mêmes raisons) Principe Général : À chaque fois qu'on veut tester l'égalité entre deux ensembles avec le symbole==
, c'est en fait la méthode magique__eq__()
qui est appelée pour tester l'égalité.
- Syntaxe normale :
Voici quelques autres méthodes magiques sur les listes :
__ne__()
veut dire \(\ne\) : "Not Equal to" c'est-à-dire Non égal, donc! =
en Python__gt__()
veut dire \(\gt\) : "Greater Than" c'est-à-dire Supérieur Strictement__ge__()
veut dire \(\ge\) : "Greater than or Equal to" c'est-à-dire Supérieur ou égal à__lt__()
veut dire \(\lt\) : "Less Than" c'est-à-dire Inférieur Strictement__le__()
veut dire \(\le\) : "Less than or Equal to" c'est-à-dire Inférieur ou égal__contains__()
correspond au mot-cléin
utilisé pour tester l'inclusion d'un ensemble dans un autre-
__or__()
veut direunion
ou bienou
ou bien|
pour réaliser l'union de deux ensembles -
__repr__()
représente une ensemble dans un interpréteur Python, c'est-à-dire qu'il affiche un ensemble dans un interpréteur Python, sous un certain format spécifique. Elle est appelée quand on tape dans l'interpréteur :
- ou bien
>>> s1
\(\quad\) (oùs1
désigne le nom d'un ensemble) - ou bien
>>> print(s1)
- ou bien
__str__()
représente un ensemble dans un interpréteur Python, c'est-à-dire qu'il affiche un ensemble dans un interpréteur Python, sous un certain format spécifique, mais seulement pour le
print()
>>> print(s1)
- etc...
Opérations Arithmétiques sur les Ensembles⚓︎
Addition⚓︎
- PAS d'addition
+
entre deux ensembles. - La soustraction
-
existe, et a été définie dans les méthodes.
Multiplication⚓︎
- PAS de produit entre deux ensembles, ni entre un ensemble et un entier
- PAS de division entre deux ensembles
Les ensembles sont mutables⚓︎
Par exemple, on peut modifier un ensemble set
in situ, par exemple avec une méthode d'ajout d'élément .add(element)
, EN CONSERVANT LA MÊME ADRESSE MÉMOIRE (qui est en fait un pointeur vers le début de l'ensemble).
>>> s = set([1,2,3])
>>> id(s) # renvoie l'adresse mémoire du début de l'ensemble
# Exemple de réponse:
140205838266432
# ajout d'élément :
>>> s.add(4)
>>> id(s) # la 'nouvelle' adresse mémoire de l'ensemble est inchangée
# (ici, ajout d'élément)
140205838266432
On s'aperçoit que les deux adresses mémoires, ou pointeurs, AVANT et APRÈS modification de l'ensemble, sont encores égales.
Mutabilité des Ensembles
Les ensembles sont mutables.
Hashabilité⚓︎
Pte
Les éléments d'un set
doivent être hashables
# en particulier: PAS de liste à l'intérieur d'un ensemble
>>> s = {[1,2,3]}
TypeError: unhashable type: 'list'
# ni d'ensemble à l'interieur d'un ensemble
>>> s = { {1,2,3}}
TypeError: unhashable type: 'set'
Hashable
Un objet est dit ) s'il a une empreinte
ou (valeur de) hash
qui ne change jamais pendant sa durée de vie :
- il doit donc implémenter une méthode
__hash__()
et - il doit être comparable à d'autres objets avec la méthode
__eq__()
(ou__cmp__()
) Deux objets hashables considérés égaux doivent avoir la même valeur de hash/empreinte.
Quels objets sont hashables ?
- La plupart des objets natifs immutables de Python sont hashables :
- Tous les types de base immutables (
int
,float
,str
) en Python sont hashables - Les conteneurs immutables (comme les
tuples
ou lesfrozensets
), sont hashables lorsque leurs éléments sont hashables.
- Tous les types de base immutables (
- Les conteneurs mutables (comme les ensembles
set
, ou les listeslist
ou les dictionnairesdict
), ne sont PAS hashables.
Utilisation des Objets Hashables
Un objet hashable peut être utilisé :
- comme clé de dictionnaire
- comme élément d'un ensemble
Remarque (Terminale NSI) :
Les instances des classes définies par l'utilisateur sont hashables par défaut. Elles sont toutes différentes entre elles (non égales, au sens de __eq__()
), et leur valeur de hash est déterminé par leur id()
.
Compréhensions d'Ensembles⚓︎
Une compréhension d'ensembles, ou ensemble en compréhension, est une syntaxe pour créer/générer un ensemble en une seule ligne de commande, en y incluant une boucle for sur une seule ligne.
Syntaxe sans if
⚓︎
# 'iterable' est un itérable : une chaîne, une liste, un tuple, un ensemble, range(), etc...
>>> {fonction(item) for item in iterable}
>>> set(fonction(item) for item in iterable)
Remarque : les chaînes, les listes, les tuples, les ensembles, range(), etc... sont des itérables.
Exp
>>> {i for i in range(5)}
>>> {i for i in [0,1,2,3,4]}
>>> {i for i in (0,1,2,3,4)}
>>> set(i for i in (0,1,2,3,4))
# Renvoient tous l'ensemble
{0, 1, 2, 3, 4}
Syntaxe avec un if
⚓︎
# 'iterable' est un itérable : une chaîne, une liste, un tuple, un ensemble, range(), etc...
>>> {fonction(item) for item in iterable if condition(item)}
>>> set(fonction(item) for item in iterable if condition(item))
Exp
>>> {i for i in range(21) if i%4!=0}
>>> set(i for i in range(21) if i%4!=0)
# Renvoient chacune :
{1, 2, 3, 5, 6, 7, 9}
if
DOIT être placé APRÈS le for
, du moins lorsque le if
est tout seul (c'est-à-dire non accompagné d'un else
). En particulier, la syntaxe suivante, que l'on pourrait naïvement croire équivalente, NE FONCTIONNE PAS:
>>> {i if i%4!=0 for i in range(21)}
>>> set(i if i%4!=0 for i in range(21))
SyntaxError: invalid syntax
Syntaxe avec un if
ET un else
⚓︎
# 'iterable' est un itérable : une chaîne, une liste, un tuple, un ensemble, range(), etc...
>>> {fonction(item) if condition(item) else autreFonction(item) for item in iterable}
>>> set(fonction(item) if condition(item) else autreFonction(item) for item in iterable)
Exp
>>> {i if i%4!=0 else "bissextile" for i in range(21)}
>>> set(i if i%4!=0 else "bissextile" for i in range(21))
# Renvoient chacune :
{1, 2, 3, 5, 6, 7, 9, 'bissextile'}
if
DOIT être placé APRÈS le for
, du moins lorsque le if
est tout seul (c'est-à-dire non accompagné d'un else
). En particulier, la syntaxe suivante, que l'on pourrait naïvement croire équivalente, NE FONCTIONNE PAS:
>>> {i for i in range(21) if i%4!=0 else "bissextile"}
>>> set(i for i in range(21) if i%4!=0 else "bissextile")
SyntaxError: invalid syntax