collections
¶
Par Cédric Pahud 1
Introduction¶
collections
contient des conteneurs de données spécialisés qui offrent une alternative aux conteneurs généraux de python.
Ces conteneurs vont souvent plus loin que les conteneurs de données built-in et ont des fonctionnalités plus avancées que nous allons voir ici.
Voici donc les conteneurs dont nous allons parler:
Conteneur |
Utilité |
---|---|
namedtuple() |
une fonction permettant de créer une sous-classe de tuple avec des champs nommés |
deque |
un conteneur ressemblant a une liste mais avec ajout et suppression rapide a chacun des bouts |
ChainMap |
permet de linker entre eux plusieurs mappings ensemble pour les gérer comme un tout |
Counter |
Permet de compter les occurences d’objets hachable |
OrderedDict |
une sous classe de dictionnaire permettant de savoir l’ordre des entrées |
defaultdict |
une sous classe de dictionnaire permettant de spécifier une valeur par défaut dans le constructeur |
namedtuple()¶
tout d’abord avant d’utiliser la fonction namedtuple()
il faut comprendre ce qu’est un tuple.
un tuple est une collection immuable de données souvent hétérogène.
>>> t = ("cheval", "voiture", "bateau")
>>> t
('cheval', 'voiture', 'bateau')
>>> t[0]
'cheval'
>>> t[-1]
'voiture'
ci-dessus on remarque qu’on peut atteindre les champs de notre tuple seulement en spécifiant son index.
En utilisant la fonction namedtuple()
pour créer notre tuple, on peut nommer ses champs.
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # instanciation par position ou en utilisant le nom du champs
>>> p[0] + p[1] # indexable comme les tuples de base (11, 22)
33
>>> x, y = p # on peut le diviser en plusieurs variables (comme un tuple normal)
>>> x, y
(11, 22)
>>> p.x + p.y # les champs sont accessibles par nom
33
>>> p # lisible dans un style nom=valeur
Point(x=11, y=22)
quelques fonctions¶
mytuple._make(iterable)¶
cette fonction permet de créer un tuple a partir d’un objet iterable.
>>> t = [11, 22]
>>> Point(*t)
Point(11, 12)
>>> Point._make(t)
Point(x=11, y=22)
mytuple._asdict()¶
cette fonction retourne un nouveau OrderedDict qui map les noms de champs avec leurs valeurs.
>>> p = Point(x=11, y=22)
>>> p._asdict()
OrderedDict([('x', 11), ('y', 22)])
mytuple._replace(key=args)¶
cette fonction permet de retourner une nouvelle instance de notre tuple avec une valeures modifiée.
>>> p = Point(x=11, y=22)
>>> p._replace(x=33)
Point(x=33, y=22)
mytuple._fields¶
cette fonction permet de récupérer les noms des champs de notre tuple. elle est utile si on veut créer un nouveau tuple avec les champs d’un tuple existant.
>>> p._fields # retourne les noms de champs
('x', 'y')
>>> Color = namedtuple('Color', 'red green blue')
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) #on créé un nouveau tuple avec les champs de point et de color
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)
deque¶
la classe collections.deque
est une généralisation des liste et des piles. les deque sont thread-safe et supporte l’ajout d’une
valeur de chaque côté (pile, liste). La preformance lors de l’ajout d’une valeur peut importe le côté
est de O(1). Même si les objets de type list supportent des opérations similaires elles sont plus optimisées
pour des opérations qui ne change pas leur taille alors qu” un pop()
ou un insert()
ont une complexité O(n).
class collections.deque([iterable[, maxlen]])
cette instruction retourne un deque contenant les valeurs de
iterable
(s’il n’est pas spécifié le deque est vide) et l’argument maxlen
permet de spécifier une taille
maximum (la taille n’a pas de limite s’il nes pas spécifié).
>>> d = deque('abc') # créé un nouveau deque avec 3 valeurs
>>> for elem in d: # itères sur les éléments de notre deque
... print(elem)
a
b
c
quelques fonctions¶
append(x), appendleft(x), extend(iterable) et extendleft(iterable)¶
append
ajoute une seule valeure du côté droit du deque et appendleft
du côté gauche
alors que extend
et extendleft
permettent d’ajouer plusieurs éléments d’un coup.
>>> d.append('z')
>>> d.appendleft('r')
>>> d
deque(['r', 'a', 'b', 'c', 'z'])
>>> d.extend('jkl')
>>> d
deque(['r', 'a', 'b', 'c', 'z','j','k','l'])
pop(), popleft(), remove(val) et clear()¶
pop
et popleft
permettent de faire sortire un objet de notre deque alors que
remove
supprime la première occurence de la val passée en paramètre et finalement
clear
vide le deque.
>>> d.clear()
>>> d.extends('abc')
>>> d.remove('b')
>>> d
deque(['a', 'c'])
>>> d.pop()
'c'
>>> d.popleft()
'a'
ChainMap¶
collections.ChainMap
permet de linker plusieurs mappings pour qu’ils soient géré comme un seul. C’est
souvent plus rapide que de créer un nouveau dictionnaire et faire plusieurs update()
.
class collections.ChainMap(*maps)
cette fonction nous retourne une nouvelle ChainMap.
Si il n’y a pas de maps spécifiés en paramètres la ChainMap sera vide.
>>> from collections import ChainMap
>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = ChainMap(y, x)
>>> for k, v in z.items():
print(k, v)
a 1
c 11
b 10
Dans cet exemple on remarque que la clé b a pris la valeur 10 et pas 2 car
y
est passé avant x
dans le constructeur de ChainMap.
Counter¶
collections.Counter
est une sous classe de dict
.
qui permet de compter des objets hachable. En fait c’est un dictionnaire avec comme clé les
éléments et comme valeurs leur nombre.
class collections.Counter([iterable-or-mapping])
ceci nous retourne un Counter. L’argument
permet de spécifier ce que l’on veut mettre dedans et qui doit être compté. Voici un exemple :
>>> c = Counter() # compteur vide
>>> c = Counter('gallahad') #compteur avec un iterable
>>> c = Counter({'red': 4, 'blue': 2}) # un compteur avec un mapping
>>> c = Counter(cats=4, dogs=8) #un compteur avec key=valeur
Contrairement à un dictionnaire si on demande une valeur n’étant pas dans notre liste
il retourne 0 et non pas KeyError
>>> c = Counter(['eggs', 'ham'])
>>> c['bacon'] # clé inconnue
0
quelques fonctions¶
elements()¶
retourne une liste de tous les éléments du compteur :
>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> sorted(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']
most_common([n])¶
retourne les n éléments les plus présents dans notre compteur :
>>> Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]
substract([iterable or mapping])¶
permet de soustraire des éléments d’un compteur (mais pas de les supprimer) :
>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> d = Counter(a=1, b=2, c=3, d=4)
>>> c.subtract(d)
>>> c
Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
OrderedDict¶
les collections.OrderedDict
sont comme les dict
.
mais ils se rappelent l’ordre d’entrée des valeurs. Si on itère dessus les données seront
retournées dans l’ordre d’ajout dans notre dict.
class collections.OrderedDict([items])
cette fonction nous retourn un OrderedDict.
Quelques méthodes¶
popitem(last=True)¶
Cette fonction fait sortir une paire clé valeur de notre dictionnaire et si
l’argument last est a `True
alors les pairs seront retournée en LIFO sinon
ce serra en FIFO.
move_to_end(key, last=True)¶
Cette fonction permet de déplacer une clé à la fin de notre dictionnaire si
last est à True
sinon au début de notre dict.
>>> d = OrderedDict.fromkeys('abcde')
>>> d.move_to_end('b')
>>> ''.join(d.keys())
'acdeb'
>>> d.move_to_end('b', last=False)
>>> ''.join(d.keys())
'bacde'
defaultdict¶
La classe collections.defaultdict
est une sous classe de dict
.
Elle ajoute une variable et une fonction à la classe dict
.
class collections.defaultdict([default_factory[, ...]])
cette commande nous retourne un objet
de type defaultdict.L’argument default_factory
est par défaut à None
et les reste des arguments
sont traité comme si on utilisait le constructeur de dict.
La fonction ajoutée par defaultdict est __missing(key)__
elle est appelée par __getitem()__
de la
classe dict
.
l’argument default_factory
permet de spécifier quelle structure de données va correspondre
à une clé dans notre defaultdict. Voici 2 exemples pour mieux comprendre:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Dans cette exemple on initialise default_factory
comme une list
ce qui nous permet d’utiliser
append()
pour ajouter des éléments à la liste correspondant à une clé donnée.
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> sorted(d.items())
[('i', 4), ('m', 1), ('p', 2), ('s', 4)]
Dans cet exemple on va utiliser un int au lieu d’une liste et notre defaultdict va s’utiliser comme un compteur.
Conclusion¶
Chacun des conteneurs vu dans ce tutoriel a une utilité bien définie alors choisissez sagement votre conteneur en fonction de votre problème pour vous simplifier la vie.
Choisir Sagement ton conteneur tu dois !
—Maître Yoda