L’auteur a choisi le COVID-19 Relief Fund pour recevoir un don dans le cadre du programme Write for DOnations.
Python 3 possède un certain nombre de structures de données intégrées, notamment des tuples, des dictionnaires et des listes. Les structures de données nous fournissent un moyen d’organiser et de stocker les données. Le module de collections
nous aide à remplir et à manipuler les structures de données de manière efficace.
Dans ce tutoriel, nous allons passer en revue trois classes des collections
pour vous aider à travailler avec des tuples, des dictionnaires et des listes. Nous utiliserons namedtuples
pour créer des tuples avec des champs nommés, defaultdict
pour regrouper de manière concise les informations dans les dictionnaires, et deque
pour ajouter efficacement des éléments de chaque côté d’un objet de type liste.
Pour ce tutoriel, nous travaillerons principalement avec un inventaire de poissons que nous devons modifier au fur et à mesure que des poissons sont ajoutés ou retirés d’un aquarium fictif.
Pour tirer le meilleur parti de ce tutoriel, il est recommandé de se familiariser avec le tuple, le dictionnaire et les types de données de liste que ce soit en ce qui concerne leur syntaxe que de la manière d’en extraire des données. Vous pouvez consulter ces tutoriels pour obtenir les informations de base nécessaires :
Les tuples de Python sont une séquence d’éléments immuables, ou inchangeables, ordonnés. Les tuples sont fréquemment utilisés pour représenter des données en colonnes ; par exemple, les lignes d’un fichier CSV ou les lignes d’une base de données SQL. Un aquarium peut garder une trace de son inventaire de poissons sous la forme d’une série de tuples.
Un tuple de poissons individuel :
("Sammy", "shark", "tank-a")
Ce tuple est composé de trois éléments de chaîne caractères.
Bien qu’utile à certains égards, ce tuple n’indique pas clairement ce que représente chacun de ses champs. En réalité, l’élément 0
est un nom, l’élément 1
est une espèce, et l’élément 2
est le réservoir de stockage.
Explication des champs de tuples de poissons :
name | species | tank |
---|---|---|
Sammy | shark | tank-a |
Ce tableau montre clairement que chacun des trois éléments du tuple a une signification claire.
namedtuple
du module collections
vous permet d’ajouter des noms explicites à chaque élément d’un tuple pour rendre ces significations claires dans votre programme Python.
Utilisons namedtuple
pour générer une classe qui nomme clairement chaque élément du tuple de poisson :
from collections import namedtuple
Fish = namedtuple("Fish", ["name", "species", "tank"])
from collections import namedtuple
donne à votre programme Python l’accès à la fonction d’usine namedtuple
. L’appel de la fonction namedtuple()
renvoie une classe qui est liée au nom Fish
. Le namedtuple()
a deux arguments : le nom souhaité de notre nouvelle classe "Fish"
et une liste d’éléments nommés ["name", "species", "tank"]
.
Nous pouvons utiliser la classe Fish
pour représenter le tuple de poissons de tout à l’heure :
sammy = Fish("Sammy", "shark", "tank-a")
print(sammy)
Si nous exécutons ce code, nous obtiendrons le résultat suivant :
OutputFish(name='Sammy', species='shark', tank='tank-a')
sammy
est instancié à l’aide de la classeFish
. sammy
est un tuple avec trois éléments clairement nommés.
Les champs de sammy
sont accessibles par leur nom ou avec un index tuple traditionnel :
print(sammy.species)
print(sammy[1])
Si nous lançons ces deux appels d’impression
, nous obtiendrons le résultat suivant :
Outputshark
shark
L’accès à .species
a la même valeur que l’accès au deuxième élément de sammy
en utilisant [1]
.
Utiliser namedtuple
du module collections
rend votre programme plus lisible tout en conservant les propriétés importantes d’un tuple (à savoir qu’ils sont immuables et ordonnés).
De plus, la fonction d’usine namedtuple
ajoute plusieurs méthodes supplémentaires aux instances de Fish
.
Utilisez ._asdict()
pour convertir une instance en dictionnaire :
print(sammy._asdict())
Si nous lançons print
, vous verrez des résultats comme ceux qui suivent :
Output{'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}
Appeler .asdict()
sur sammy
renvoie un dictionnaire mettant en correspondance les noms de chacun des trois champs avec leurs valeurs correspondantes.
Les versions de Python plus anciennes que 3.8 pourraient produire cette ligne de manière légèrement différente. Vous pourriez, par exemple, voir un OrderedDict
au lieu du simple dictionnaire présenté ici.
Note : Dans Python, les méthodes avec des traits de soulignement en tête sont généralement considérées comme « privées ». Les méthodes supplémentaires fournies par namedtuple
(comme _asdict()
, ._make()
, ._replace()
, etc.), sont toutefois publiques.
Il est souvent utile de collecter des données dans les dictionnaires Python. defaulttdict
du module de collections
peut nous aider à rassembler les informations dans les dictionnaires de manière rapide et concise.
defaultdict
ne soulève jamais une KeyError
. Si une clé n’est pas présente, defaulttdict
se contente d’insérer et de renvoyer une valeur de remplacement à la place :
from collections import defaultdict
my_defaultdict = defaultdict(list)
print(my_defaultdict["missing"])
Si nous exécutons ce code, nous obtiendrons le résultat suivant :
Output[]
defaultdict
insère et renvoie une valeur de remplacement au lieu de lancer une KeyError
. Dans ce cas, nous avons spécifié la valeur de remplacement sous forme de liste.
Les dictionnaires ordinaires, en revanche, lancent une KeyError
sur les clés manquantes :
my_regular_dict = {}
my_regular_dict["missing"]
Si nous exécutons ce code, nous obtiendrons le résultat suivant :
OutputTraceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'missing'
Le dictionnaire habituel my_regular_dict
soulève une KeyError
lorsque nous essayons d’accéder à une clé qui n’est pas présente.
defaulttdict
se comporte différemment d’un dictionnaire ordinaire. Au lieu de soulever une KeyError
sur une clé manquante, defaultdict
appelle la valeur de remplacement sans argument pour créer un nouvel objet. Dans ce cas, list()
pour créer une liste vide.
Pour continuer avec notre exemple d’aquarium fictif, disons que nous avons une liste de tuples de poissons représentant l’inventaire d’un aquarium :
fish_inventory = [
("Sammy", "shark", "tank-a"),
("Jamie", "cuttlefish", "tank-b"),
("Mary", "squid", "tank-a"),
]
Trois poissons existent dans l’aquarium - leur nom, leur espèce et leur bac de rétention sont notés dans ces trois tuples.
Notre objectif est d’organiser notre inventaire par réservoir - nous voulons connaître la liste des poissons présents dans chaque réservoir. En d’autres termes, nous voulons un dictionnaire qui cartographie "tank-a"
. à ["Jamie", "Mary"]
et "tank-b"
à ["Jamie"]
.
Nous pouvons utiliser defaulttdict
pour regrouper les poissons par bassin :
from collections import defaultdict
fish_inventory = [
("Sammy", "shark", "tank-a"),
("Jamie", "cuttlefish", "tank-b"),
("Mary", "squid", "tank-a"),
]
fish_names_by_tank = defaultdict(list)
for name, species, tank in fish_inventory:
fish_names_by_tank[tank].append(name)
print(fish_names_by_tank)
En exécutant ce code, nous obtiendrons le résultat suivant :
Outputdefaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})
fish_names_by_tank
est déclaré comme un paramètre par défaut
qui consiste par défaut à insérer list()
au lieu de lancer une KeyError
. Comme cela garantit que chaque clé dansfish_names_by_tank
pointera sur une liste
, nous pouvons librement appeler .append()
pour ajouter des noms à la liste de chaque réservoir.
defaultdict
vous aide ici car il réduit le risque d’erreurs inattendues de KeyErrors
. Réduire lesKeyErrors
inattendues signifie que votre programme peut être écrit plus clairement et avec moins de lignes. Plus concrètement, l’idiome defaultdict
permet d’éviter d’instancier manuellement une liste vide pour chaque réservoir.
Sans défaultdict
, le corps de la boucle for
aurait pu ressembler davantage à ceci :
...
fish_names_by_tank = {}
for name, species, tank in fish_inventory:
if tank not in fish_names_by_tank:
fish_names_by_tank[tank] = []
fish_names_by_tank[tank].append(name)
L’utilisation d’un simple dictionnaire (au lieu d’un defaultdict
) signifie que le corps de la boucle for
doit toujours vérifier l’existence du tank
donné dans fish_names_by_tank
. Ce n’est qu’après avoir vérifié que tank
est déjà présent dans fish_names_by_tank
, ou vient d’être initialisé avec un []
, qu’on peut ajouter le nom du poisson.
defaultdict
peut aider à réduire le nombre de codes passe-partout lors du remplissage des dictionnaires car il ne provoque jamais de KeyError
.
Les listes Python sont une séquence d’éléments ordonnée, mutable ou modifiable. Python peut ajouter des listes en temps constant (la longueur de la liste n’a aucun effet sur le temps qu’il faut pour l’ajout), mais l’insertion au début d’une liste peut être plus lente (le temps nécessaire augmente à mesure que la liste s’agrandit).
En termes de notation Big O, l’ajout à une liste est une opération O(1)
à temps constant. L’insertion au début d’une liste, en revanche, est plus lente avec O(n)
performance.
Note : Les informaticiens mesurent souvent la performance des procédures en utilisant ce qu’on appelle la notation « Big O ». Lorsque la taille d’une entrée n’a aucun effet sur le temps nécessaire pour exécuter une procédure, on dit qu’elle se déroule en temps constant ou O(1)
(“Big O of 1”). Comme vous l’avez appris plus haut, Python peut s’ajouter aux listes à performance temporelle constante, autrement dit O(1)
.
Parfois, la taille d’une entrée a une incidence directe sur le temps nécessaire à l’exécution d’une procédure. L’insertion au début d’une liste Python, par exemple, est d’autant plus lente qu’il y a plus d’éléments dans la liste. La notation Big O utilise la lettre n
pour représenter la taille de l’entrée. Cela signifie que l’ajout d’éléments au début d’une liste Python se fait en « temps linéaire » ou O(n)
(“Big O of n”).
En général, les procédures O(1)
sont plus rapides que les procédures O(n)
.
On peut l’insérer au début d’une liste Python :
favorite_fish_list = ["Sammy", "Jamie", "Mary"]
# O(n) performance
favorite_fish_list.insert(0, "Alice")
print(favorite_fish_list)
Si nous exécutons ce qui suit, nous obtiendrons le résultat suivant :
Output['Alice', 'Sammy', 'Jamie', 'Mary']
La méthode .insert (index, objet)
sur list nous permet d’insérer "Alice"
au début de favorite_fish_list
. Toutefois, il est à noter que l’insertion au début d’une liste a O(n)
performance. Comme la durée de favorite_fish_list
augmente, le temps nécessaire pour insérer un poisson au début de la liste augmentera proportionnellement et prendra de plus en plus de temps.
deque
(prononcé « deck ») du module collections
est un objet de type liste qui nous permet d’insérer des éléments au début ou à la fin d’une séquence avec une performance à temps constant (O(1)
).
Insérez un élément au début d’un deque
:
from collections import deque
favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
# O(1) performance
favorite_fish_deque.appendleft("Alice")
print(favorite_fish_deque)
En exécutant ce code, nous obtiendrons le résultat suivant :
Outputdeque(['Alice', 'Sammy', 'Jamie', 'Mary'])
Nous pouvons instancier un deque
en utilisant un ensemble d’éléments préexistants, en l’occurrence une liste de trois noms de poissons favoris. L’appel de la méthode appendleft
de favorite_fish_deque
nous permet d’insérer un élément au début de notre collection avec la performance O (1)
. O(1)
performance signifie que le temps nécessaire pour ajouter un élément au début de favorite_fish_deque
n’augmentera pas, même si favorite_fish_deque
a des milliers ou des millions d’éléments.
Note : Bien que deque
ajoute des entrées au début d’une séquence plus efficacement qu’une liste, deque
n’effectue pas toutes ses opérations plus efficacement qu’une liste. Par exemple, l’accès à un article aléatoire dans un deque
a une performance O(n)
, mais l’accès à un élément aléatoire d’une liste a une performance O(1)
. Utilisez deque
lorsqu’il est important d’insérer ou de retirer rapidement des éléments de chaque côté de votre collection. Une comparaison complète des performances temporelles est disponible sur le wiki de Python.
Le module des collections
est une partie puissante de la bibliothèque standard Python qui vous permet de travailler avec des données de manière concise et efficace. Ce tutoriel couvrait trois des cours fournis par le module des collections
comprenant namedtuple
, defaultdict
, et deque
.
D’ici, vous pouvez utiliser la documentation du module de collecte
pour en savoir plus sur les autres classes et utilités disponibles. Pour en savoir plus sur Python en général, vous pouvez lire notre Série de tutoriels Comment coder en Python 3.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!