2.10. Ensembles¶
Un ensemble (set) est une collection non ordonnée d’éléments uniques. Ajouter une valeur déjà présente n’a aucun effet ; l’itération produit chaque valeur exactement une fois. Les ensembles sont l’outil approprié lorsque l’appartenance et la déduplication importent, mais pas l’ordre.
2.10.1. Créer un ensemble¶
Utilisez des accolades pour un ensemble non vide, ou set() pour un ensemble vide :
colours = {"red", "green", "blue"}
empty = set()
Les accolades ressemblent à un littéral dict ; {} seul est un dictionnaire vide, et non un ensemble vide – l’un des accidents historiques de Python. Utilisez set() pour le cas vide.
set() construit aussi un ensemble à partir de n’importe quel itérable, ce qui est la manière standard d’éliminer les doublons d’une séquence :
nums = [1, 2, 2, 3, 1, 4]
unique = set(nums)
print(unique)
Sortie
{1, 2, 3, 4}
L’ordre d’affichage peut varier – les ensembles ne garantissent aucun ordre d’itération particulier.
2.10.2. Ensemble (set) ou dictionnaire (dict)¶
Les ensembles et les dictionnaires stockent tous deux des éléments uniques dans une table de hachage. La différence réside dans ce que chaque élément transporte avec lui :
Un
dictstocke des paires clé-valeur. Rechercher une clé renvoie sa valeur.Un
setstocke uniquement les éléments. Rechercher un élément vous indique s’il est présent.
Le choix entre les deux dépend de la question de savoir si la valeur associée à chaque élément a une signification :
Optez pour un ensemble lorsqu’aucune valeur n’accompagne chaque élément – vous voulez seulement savoir si l’élément est présent, ou vous combinez des groupes d’éléments uniques par union / intersection.
Optez pour un dictionnaire lorsque chaque élément est associé à des données que la recherche est censée récupérer – une table de configuration, un cache, un compteur indexé par nom.
Les deux types partagent une grande partie de leur syntaxe de surface, ce qui est à l’origine de la plupart des confusions. Les différences en un seul bloc :
set |
dict |
|
|---|---|---|
contient |
des éléments uniques |
des clés uniques, chacune avec une valeur |
littéral rempli |
|
|
littéral vide |
|
|
test d’appartenance |
|
|
récupérer une valeur |
s/o |
|
ajouter un élément |
|
|
itérer |
produit des éléments |
produit des clés (utilisez |
L’asymétrie entre les littéraux remplis et vides est le piège qui mérite d’être souligné :
Des accolades contenant des éléments –
{1, 2, 3}– forment un littéral d’ensemble ; des accolades contenant des paires clé-valeur –{"a": 1}– forment un littéral de dictionnaire. L’analyseur les distingue par leur contenu.Des accolades vides –
{}– forment un dictionnaire vide, et non un ensemble vide. Les dictionnaires sont apparus en premier ; le littéral vide leur appartient. Un ensemble vide n’a aucun littéral à accolades et doit s’écrireset().
Un schéma courant, lorsque seules les clés d’un dictionnaire sont jamais lues, consiste à passer à un ensemble – cela rend l’intention évidente et élimine les valeurs inutilisées de la mémoire.
2.10.3. Ajouter et supprimer¶
set.add()– insère un élément.set.discard()– supprime un élément s’il est présent, ne fait rien sinon.set.remove()– supprime un élément ; déclenche uneKeyErrors’il est absent.set.clear()– vide l’ensemble.
s = {1, 2, 3}
s.add(4)
s.discard(99) # silent: 99 not in s
s.remove(2)
print(s)
Sortie
{1, 3, 4}
2.10.4. Appartenance¶
L’opérateur in teste l’appartenance. Sur un ensemble, son temps d’exécution est approximativement constant quelle que soit la taille – ce qui est la principale raison de choisir un ensemble plutôt qu’une list lorsque vous avez seulement besoin de demander « cette valeur s’y trouve-t-elle » :
if "red" in colours:
print("colour is allowed")
Une list au contenu identique serait parcourue depuis le début à chaque fois, ce qui convient pour dix éléments mais devient lent pour dix mille.
2.10.5. Opérations sur les ensembles¶
Deux ensembles peuvent être combinés avec les opérations mathématiques habituelles. Chacune a à la fois une forme opérateur et une forme méthode :
a | boua.union(b)– tout ce qui se trouve dans l’un ou l’autre ensemble.a & boua.intersection(b)– seulement ce qui apparaît dans les deux.a - boua.difference(b)– ce qui est dansamais pas dansb.a ^ boua.symmetric_difference(b)– ce qui est dans l’un mais pas dans les deux.
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b)
print(a & b)
print(a - b)
print(a ^ b)
Sortie
{1, 2, 3, 4, 5, 6}
{3, 4}
{1, 2}
{1, 2, 5, 6}
Les formes opérateur sont en lecture seule ; les formes méthode acceptent n’importe quel itérable à droite, pas seulement un autre ensemble (a.union([5, 6])). Choisissez celle qui se lit le mieux dans le contexte.
2.10.6. Ce qui peut figurer dans un ensemble¶
Les éléments d’un ensemble doivent être hachables – la même contrainte que pour les clés de dict. int, float, str, bool, bytes et tuple (lorsque son contenu est lui-même hachable) fonctionnent tous. list et dict non ; tenter d’en ajouter un déclenche une TypeError.
2.10.7. frozenset¶
Un set ordinaire est mutable : chaque appel à add / remove / discard modifie l’objet sur place. Cette mutabilité l’empêche d’être hachable, de sorte qu’un ensemble ne peut pas servir de clé de dict ni d’élément d’un autre ensemble.
frozenset en est l’équivalent immuable. Il dispose des mêmes recherches et opérateurs (in, |, &, -, ^) que set, mais sans add / remove ni aucune méthode qui mute. Comme rien ne peut jamais modifier son contenu, le hachage d’un frozenset est bien défini – il est donc hachable :
primary = frozenset({"red", "green", "blue"})
secondary = frozenset({"yellow", "purple", "orange"})
palettes = {
primary: "RGB",
secondary: "mixed",
}
print(palettes[primary])
Sortie
RGB
Construisez un frozenset à partir de n’importe quel itérable – frozenset() pour le cas vide, frozenset(some_set) pour prendre un instantané immuable d’un ensemble existant :
snapshot = frozenset(s) # immutable copy of s
s.add("new") # snapshot does not change
Deux raisons courantes d’y recourir :
Utilisation comme clé de dictionnaire ou élément d’ensemble. Partout où une valeur unique ne peut pas capturer ce dont vous avez besoin, un
frozensetde valeurs le peut – « l’ensemble des caractéristiques prises en charge par ce pilote », « l’ensemble des broches qu’utilise ce profil ».Verrouiller une constante. Un
frozensetau niveau du module contenant les noms autorisés ne peut pas être accidentellement muté par un appelant ; unsetordinaire le peut. Préférezfrozensetpour tout ce qui est censé être en lecture seule après sa construction.