collections
--- Container datatypes¶
Code source : Lib/collections/__init__.py
Ce module implémente des types de données de conteneurs spécialisés qui apportent des alternatives aux conteneurs natifs de Python plus généraux dict
, list
, set
et tuple
.
fonction permettant de créer des sous-classes de |
|
conteneur se comportant comme une liste avec des ajouts et retraits rapides à chaque extrémité |
|
classe semblable aux dictionnaires qui crée une unique vue à partir de plusieurs dictionnaires |
|
dict subclass for counting hashable objects |
|
sous-classe de |
|
sous-classe de |
|
surcouche autour des objets dictionnaires pour faciliter l'héritage de |
|
surcouche autour des objets listes pour faciliter l'héritage de |
|
surcouche autour des objets chaînes de caractères pour faciliter l'héritage de |
Objets ChainMap
¶
Ajouté dans la version 3.3.
Le module fournit une classe ChainMap
afin de réunir rapidement plusieurs dictionnaires en une unique entité. Cela est souvent plus rapide que de créer un nouveau dictionnaire et d'effectuer plusieurs appels de update()
.
Cette classe peut être utilisée pour simuler des portées imbriquées, elle est aussi utile pour le templating.
- class collections.ChainMap(*maps)¶
Un objet
ChainMap
regroupe plusieurs dictionnaires (ou autres tableaux de correspondance) en une vue que l'on peut mettre à jour. Si le paramètre maps est vide, un dictionnaire vide est fourni de telle manière qu'une nouvelle chaîne possède toujours au moins un dictionnaire.Les dictionnaires sous-jacents sont stockés dans une liste. Celle-ci est publique et peut être consultée ou mise à jour via l'attribut maps. Il n'y a pas d'autre état.
Les recherches s'effectuent successivement dans chaque dictionnaire jusqu'à la première clé correspondante. En revanche, les écritures, mises à jour et suppressions n'affectent que le premier dictionnaire.
Un objet
ChainMap
incorpore les dictionnaires sous-jacents par leur référence. Ainsi, si l'un d'eux est modifié, les changements affectent également laChainMap
.Toutes les méthodes usuelles des dictionnaires sont gérées. De plus, cette classe fournit un attribut maps, une méthode pour créer de nouveaux sous-contextes et une propriété pour accéder à tous les dictionnaires sous-jacents excepté le premier :
- maps¶
Liste de dictionnaires éditable par l'utilisateur et classée selon l'ordre de recherche. Il s'agit de l'unique état stocké et elle peut être modifiée pour changer l'ordre de recherche. La liste doit toujours contenir au moins un dictionnaire.
- new_child(m=None, **kwargs)¶
Renvoie un nouvel objet
ChainMap
contenant un nouveau dictionnaire suivi par tous les autres de l'instance actuelle. Sim
est spécifié, il devient le nouveau dictionnaire au début de la liste ; sinon, un dictionnaire vide est utilisé, de telle manière qu'appelerd.new_child()
équivaut à appelerChainMap({}, *d.maps)
. Si des arguments sont passés par mot-clé, ils sont insérés comme de nouvelles entrées du dictionnaire ajouté. Cette méthode est utile pour créer des sous-contextes qui peuvent être mis à jour sans altérer les valeurs dans les dictionnaires parents.Modifié dans la version 3.4: ajout du paramètre optionnel
m
.Modifié dans la version 3.10: prise en charge des arguments par mot-clé.
- parents¶
Propriété qui renvoie un nouvel objet
ChainMap
contenant tous les dictionnaires de l'instance actuelle hormis le premier. Cette propriété est utile pour ignorer le premier dictionnaire dans les recherches ; son utilisation rappelle le mot-clénonlocal
(utilisé pour les portées imbriquées), ou bien la fonction nativesuper()
. Une référence àd.parents
est équivalente à :ChainMap(*d.maps[1:])
.
Note, the iteration order of a
ChainMap
is determined by scanning the mappings last to first:>>> baseline = {'music': 'bach', 'art': 'rembrandt'} >>> adjustments = {'art': 'van gogh', 'opera': 'carmen'} >>> list(ChainMap(adjustments, baseline)) ['music', 'art', 'opera']
Cela produit le même ordre qu'une suite d'appels à
dict.update()
en commençant par le dernier tableau de correspondances :>>> combined = baseline.copy() >>> combined.update(adjustments) >>> list(combined) ['music', 'art', 'opera']
Modifié dans la version 3.9: Ajout de la gestion des opérateurs
|
et|=
tels que définis dans PEP 584.
Voir aussi
La classe MultiContext dans le package CodeTools d'Enthought possède des options pour gérer l'écriture dans n'importe quel dictionnaire de la chaîne.
La classe de contexte de Django pour la création de modèles est une chaîne de dictionnaires en lecture seule. Elle comporte également des fonctionnalités d'ajouts et de retraits de contextes similaires à la méthode
new_child()
et à la propriétéparents
.The Nested Contexts recipe has options to control whether writes and other mutations apply only to the first mapping or to any mapping in the chain.
Une version grandement simplifiée de Chainmap en lecture seule.
Exemples et cas pratiques utilisant ChainMap
¶
Cette partie montre diverses approches afin de travailler avec les dictionnaires chaînés.
Exemple 1 : simulation de la chaîne de recherche interne de Python :
import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))
Exemple 2 : spécification d'une hiérarchie pour les options : ligne de commande, variable d'environnement, valeurs par défaut :
import os, argparse
defaults = {'color': 'red', 'user': 'guest'}
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}
combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
print(combined['user'])
Exemple 3 : modèles pour simuler des contextes imbriqués avec la classe ChainMap
:
c = ChainMap() # Create root context
d = c.new_child() # Create nested child context
e = c.new_child() # Child of c, independent from d
e.maps[0] # Current context dictionary -- like Python's locals()
e.maps[-1] # Root context -- like Python's globals()
e.parents # Enclosing context chain -- like Python's nonlocals
d['x'] = 1 # Set value in current context
d['x'] # Get first key in the chain of contexts
del d['x'] # Delete from current context
list(d) # All nested values
k in d # Check all nested values
len(d) # Number of nested values
d.items() # All nested items
dict(d) # Flatten into a regular dictionary
La classe ChainMap
ne met à jour (écriture et suppression) que le premier dictionnaire de la chaîne, alors qu'une recherche inspecte toute la chaîne. Cependant, si l'on veut effectuer des écritures ou suppressions en profondeur, on peut facilement faire une sous-classe qui met à jour les clés trouvées de la chaîne en profondeur :
class DeepChainMap(ChainMap):
'Variant of ChainMap that allows direct updates to inner scopes'
def __setitem__(self, key, value):
for mapping in self.maps:
if key in mapping:
mapping[key] = value
return
self.maps[0][key] = value
def __delitem__(self, key):
for mapping in self.maps:
if key in mapping:
del mapping[key]
return
raise KeyError(key)
>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange' # update an existing key two levels down
>>> d['snake'] = 'red' # new keys get added to the topmost dict
>>> del d['elephant'] # remove an existing key one level down
>>> d # display result
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})
Objets Counter
¶
Ce module fournit un outil pour effectuer rapidement et facilement des dénombrements. Par exemple :
>>> # Tally occurrences of words in a list
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
... cnt[word] += 1
...
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})
>>> # Find the ten most common words in Hamlet
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
('you', 554), ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
- class collections.Counter([iterable-or-mapping])¶
A
Counter
is adict
subclass for counting hashable objects. It is a collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts. TheCounter
class is similar to bags or multisets in other languages.Les éléments sont comptés à partir d'un itérable ou initialisés à partir d'un autre dictionnaire (ou compteur) :
>>> c = Counter() # a new, empty counter >>> c = Counter('gallahad') # a new counter from an iterable >>> c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping >>> c = Counter(cats=4, dogs=8) # a new counter from keyword args
Les objets Counter ont une interface de dictionnaire, à l'exception près qu'ils renvoient zéro au lieu de lever une exception
KeyError
pour des éléments manquants :>>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # count of a missing element is zero 0
Mettre un comptage à zéro pour un élément ne le retire pas de l'objet Counter. Il faut utiliser
del
pour le supprimer complètement :>>> c['sausage'] = 0 # counter entry with a zero count >>> del c['sausage'] # del actually removes the entry
Ajouté dans la version 3.1.
Modifié dans la version 3.7: As a
dict
subclass,Counter
inherited the capability to remember insertion order. Math operations on Counter objects also preserve order. Results are ordered according to when an element is first encountered in the left operand and then by the order encountered in the right operand.Counter objects support additional methods beyond those available for all dictionaries:
- elements()¶
Renvoie un itérateur sur chaque élément en le répétant autant de fois que la valeur du compteur associé. Les éléments sont renvoyés dans l'ordre selon lequel ils sont rencontrés pour la première fois. Si le comptage d'un élément est strictement inférieur à 1, alors
elements()
l'ignore.>>> c = Counter(a=4, b=2, c=0, d=-2) >>> sorted(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b']
- most_common([n])¶
Renvoie une liste des n éléments les plus nombreux et leur valeur respective dans l'ordre décroissant. Si n n'est pas fourni ou vaut
None
,most_common()
renvoie tous les éléments du compteur. Les éléments qui ont le même nombre d'occurrences sont ordonnés par l'ordre selon lequel ils ont été rencontrés pour la première fois :>>> Counter('abracadabra').most_common(3) [('a', 5), ('b', 2), ('r', 2)]
- subtract([iterable-or-mapping])¶
Les éléments sont soustraits à partir d'un itérable ou d'un autre dictionnaire (ou compteur). Cette méthode se comporte comme
dict.update()
mais soustrait les nombres d'occurrences au lieu de les remplacer. Les entrées et sorties peuvent être négatives ou nulles.>>> 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})
Ajouté dans la version 3.2.
- total()¶
Calcule la somme totale des nombres d'occurrences.
>>> c = Counter(a=10, b=5, c=0) >>> c.total() 15
Ajouté dans la version 3.10.
Les méthodes usuelles des dictionnaires sont disponibles pour les objets
Counter
à l'exception de deux méthodes qui fonctionnent différemment pour les compteurs.- update([iterable-or-mapping])¶
Les éléments sont comptés à partir d'un itérable ou ajoutés d'un autre dictionnaire (ou compteur). Cette méthode se comporte comme
dict.update()
mais additionne les nombres d'occurrences au lieu de les remplacer. De plus, l'itérable doit être une séquence d'éléments et non une séquence de paires(clé, valeur)
.
Les compteurs prennent en charge les comparaisons riches pour les tests d'égalité ainsi que d'inclusion du membre gauche dans le membre droite et réciproquement, avec les opérateurs ==
, !=
, <
, <=
, >
et >=
. Les éléments dont le nombre d'occurrences est à zéro sont ignorés. Par exemple, on a Counter(a=1) == Counter(a=1, b=0)
.
Modifié dans la version 3.10: ajout des comparaisons riches.
Modifié dans la version 3.10: les éléments dont le nombre d'occurrences est à zéro sont désormais ignorés dans les tests d'égalité. On avait auparavant Counter(a=3) != Counter(a=3, b=0)
.
Opérations usuelles sur les objets Counter
:
c.total() # total of all counts
c.clear() # reset all counts
list(c) # list unique elements
set(c) # convert to a set
dict(c) # convert to a regular dictionary
c.items() # access the (elem, cnt) pairs
Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1] # n least common elements
+c # remove zero and negative counts
Several mathematical operations are provided for combining Counter
objects to produce multisets (counters that have counts greater than zero).
Addition and subtraction combine counters by adding or subtracting the counts
of corresponding elements. Intersection and union return the minimum and
maximum of corresponding counts. Equality and inclusion compare
corresponding counts. Each operation can accept inputs with signed
counts, but the output will exclude results with counts of zero or less.
>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d # add two counters together: c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d # intersection: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d # union: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
>>> c == d # equality: c[x] == d[x]
False
>>> c <= d # inclusion: c[x] <= d[x]
False
L'addition et la soustraction unaires (avec un seul terme) sont des raccourcis pour respectivement additionner un compteur avec un compteur vide ou et pour retrancher un compteur d'un compteur vide.
>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})
Ajouté dans la version 3.3: Ajout de la gestion des additions et soustractions unaires, et des remplacements dans les multiensembles.
Note
Les compteurs ont été conçus essentiellement pour fonctionner avec des entiers naturels pour représenter les dénombrements en cours ; cependant, les cas d'utilisation nécessitant d'autres types ou des valeurs négatives n'ont pas été écartés. Pour vous aider dans ces cas particuliers, cette section documente la plage minimale et les restrictions de type.
La classe
Counter
est elle-même une sous-classe de dictionnaire sans restriction particulière sur ces clés ou valeurs. Les valeurs ont vocation à être des nombres représentants des comptages, mais il est possible de stocker n'importe quel type de valeur.La méthode
most_common()
exige uniquement que les valeurs soient ordonnables.Les opérations de remplacement telles que
c[key] += 1
exigent une valeur dont le type gère l'addition et la soustraction. Cela inclut donc les fractions, les flottants et les décimaux, y compris négatifs. Il en va de même pourupdate()
etsubstract()
qui acceptent des valeurs négatives ou nulles dans les entrées et sorties.Les méthodes de multiensembles sont uniquement conçues pour les cas d'utilisation avec des valeurs positives. Les entrées peuvent contenir des valeurs négatives ou nulles, mais seules les sorties avec des valeurs positives sont créées. Il n'y a pas de restriction de type, mais les types des valeurs doivent gérer l'addition, la soustraction et la comparaison.
La méthode
elements()
exige des valeurs entières et ignore les valeurs négatives ou nulles.
Voir aussi
Bag class dans Smalltalk.
L'article Wikipédia sur les multiensembles sur Wikipédia (ou l'article en anglais).
Des guides et exemples à propos des multiensembles en C++.
Pour les opérations mathématiques sur les multiensembles et leurs applications, voir Knuth, Donald. The Art of Computer Programming Volume II, Section 4.6.3, Exercise 19.
Pour lister tous les multiensembles distincts de même taille parmi un ensemble donné d'éléments, voir
itertools.combinations_with_replacement()
:map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC
Objets deque
¶
- class collections.deque([iterable[, maxlen]])¶
Renvoie un nouvel objet deque initialisé de gauche à droite (en utilisant
append()
) avec les données d'iterable. Si iterable n'est pas spécifié, alors la nouvelle deque est vide.Deques are a generalization of stacks and queues (the name is pronounced "deck" and is short for "double-ended queue"). Deques support thread-safe, memory efficient appends and pops from either side of the deque with approximately the same O(1) performance in either direction.
Though
list
objects support similar operations, they are optimized for fast fixed-length operations and incur O(n) memory movement costs forpop(0)
andinsert(0, v)
operations which change both the size and position of the underlying data representation.Si maxlen n'est pas spécifié ou vaut None, les deques peuvent atteindre une taille arbitraire. Sinon, la deque est limitée par cette taille maximale. Une fois que celle-ci est atteinte, un ajout d'un ou plusieurs éléments engendre la suppression du nombre correspondant d'éléments à l'autre extrémité de la deque. Les deques à longueur limitée apportent des fonctionnalités similaires au filtre
tail
d'Unix. Elles sont aussi utiles pour le suivi de transactions et autres lots de données où seule l'activité récente est intéressante.Les objets deques gèrent les méthodes suivantes :
- append(x)¶
Ajoute x à l'extrémité droite de la deque.
- appendleft(x)¶
Ajoute x à l'extrémité gauche de la deque.
- clear()¶
Supprime tous les éléments de la deque et la laisse avec une longueur de 0.
- copy()¶
Crée une copie superficielle de la deque.
Ajouté dans la version 3.5.
- count(x)¶
Compte le nombre d'éléments de la deque égaux à x.
Ajouté dans la version 3.2.
- extend(iterable)¶
Étend la deque en ajoutant les éléments de l'itérable en argument à son extrémité droite.
- extendleft(iterable)¶
Étend la deque en ajoutant les éléments d'iterable à son extrémité gauche. Dans ce cas, notez que la série d'ajouts inverse l'ordre des éléments de l'argument itérable.
- index(x[, start[, stop]])¶
Renvoie la position de x dans la deque (à partir de start inclus et jusqu'à stop exclus). Renvoie la première correspondance ou lève
ValueError
si aucune n'est trouvée.Ajouté dans la version 3.5.
- insert(i, x)¶
Insère x dans la deque à la position i.
Si une insertion provoque un dépassement de la taille limitée d'une deque, alors elle lève une exception
IndexError
.Ajouté dans la version 3.5.
- pop()¶
Retire et renvoie un élément de l'extrémité droite de la deque. S'il n'y a aucun élément, lève une exception
IndexError
.
- popleft()¶
Retire et renvoie un élément de l'extrémité gauche de la deque. S'il n'y a aucun élément, lève une exception
IndexError
.
- remove(value)¶
Supprime la première occurrence de value. Si aucune occurrence n'est trouvée, lève une exception
ValueError
.
- reverse()¶
Inverse le sens des éléments de la deque sans créer de copie et renvoie
None
.Ajouté dans la version 3.2.
- rotate(n=1)¶
Décale les éléments de la deque de n places vers la droite (le dernier élément revient au début). Si n est négatif, décale vers la gauche.
Quand la deque n'est pas vide, un décalage d'une place vers la droite équivaut à
d.appendleft(d.pop())
et un décalage d'une place vers la gauche est équivalent àd.append(d.popleft())
.
Les objets deques fournissent également un attribut en lecture seule :
- maxlen¶
La taille maximale d'une deque, ou
None
si illimitée.Ajouté dans la version 3.1.
In addition to the above, deques support iteration, pickling, len(d)
,
reversed(d)
, copy.copy(d)
, copy.deepcopy(d)
, membership testing with
the in
operator, and subscript references such as d[0]
to access
the first element. Indexed access is O(1) at both ends but slows to O(n) in
the middle. For fast random access, use lists instead.
Depuis la version 3.5, les deques gèrent __add__()
, __mul__()
et __imul__()
.
Exemple :
>>> from collections import deque
>>> d = deque('ghi') # make a new deque with three items
>>> for elem in d: # iterate over the deque's elements
... print(elem.upper())
G
H
I
>>> d.append('j') # add a new entry to the right side
>>> d.appendleft('f') # add a new entry to the left side
>>> d # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])
>>> d.pop() # return and remove the rightmost item
'j'
>>> d.popleft() # return and remove the leftmost item
'f'
>>> list(d) # list the contents of the deque
['g', 'h', 'i']
>>> d[0] # peek at leftmost item
'g'
>>> d[-1] # peek at rightmost item
'i'
>>> list(reversed(d)) # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d # search the deque
True
>>> d.extend('jkl') # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1) # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1) # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> deque(reversed(d)) # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear() # empty the deque
>>> d.pop() # cannot pop from an empty deque
Traceback (most recent call last):
File "<pyshell#6>", line 1, in -toplevel-
d.pop()
IndexError: pop from an empty deque
>>> d.extendleft('abc') # extendleft() reverses the input order
>>> d
deque(['c', 'b', 'a'])
Cas pratiques utilisant deque
¶
Cette partie montre diverses approches afin de travailler avec les deques.
Les deques à taille limitée apportent une fonctionnalité similaire au filtre tail
d'Unix :
def tail(filename, n=10):
'Return the last n lines of a file'
with open(filename) as f:
return deque(f, n)
Une autre approche d'utilisation des deques est de maintenir une séquence d'éléments récemment ajoutés en les ajoutant à droite et en retirant les anciens par la gauche :
def moving_average(iterable, n=3):
# moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
# https://en.wikipedia.org/wiki/Moving_average
it = iter(iterable)
d = deque(itertools.islice(it, n-1))
d.appendleft(0)
s = sum(d)
for elem in it:
s += elem - d.popleft()
d.append(elem)
yield s / n
Un ordonnancement en round-robin peut être implémenté avec des entrées itérateurs stockées dans une deque
. Les valeurs sont produites par l'itérateur actif en position zéro. Si cet itérateur est épuisé, il peut être retiré avec la méthode popleft()
; ou bien il peut être remis à la fin avec la méthode rotate()
:
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
iterators = deque(map(iter, iterables))
while iterators:
try:
while True:
yield next(iterators[0])
iterators.rotate(-1)
except StopIteration:
# Remove an exhausted iterator.
iterators.popleft()
La méthode rotate()
apporte une façon d'implémenter la sélection d'intervalle (slicing) et les suppressions pour les deques
. Par exemple, une implémentation de del d[n]
en Python pur utilise la méthode rotate()
pour mettre en position les éléments à éjecter :
def delete_nth(d, n):
d.rotate(-n)
d.popleft()
d.rotate(n)
Pour implémenter le slicing pour les deques
, il est possible d'utiliser une approche similaire en appliquant rotate()
afin d'apporter un élément cible à l'extrémité gauche de la deque. On éjecte les anciennes entrées avec popleft()
et on ajoute les nouvelles avec extend()
, puis on inverse la rotation. Il est aisé d'implémenter les manipulations des piles inspirées du Forth telles que dup
, drop
, swap
, over
, pick
, rot
et roll
.
Objets defaultdict
¶
- class collections.defaultdict(default_factory=None, /[, ...])¶
Renvoie un nouvel objet qui se comporte comme un dictionnaire.
defaultdict
est une sous-classe de la classe nativedict
. Elle surcharge une méthode et ajoute une variable d'instance modifiable. Les autres fonctionnalités sont les mêmes que celles des objetsdict
et ne sont pas documentées ici.Le premier argument fournit la valeur initiale de l'attribut
default_factory
qui doit être un objet appelable sans paramètre ouNone
, sa valeur par défaut. Tous les autres arguments sont traités comme si on les passait au constructeur dedict
, y compris les arguments nommés.En plus des opérations usuelles de
dict
, les objetsdefaultdict
gèrent les méthodes supplémentaires suivantes :- __missing__(key)¶
Si l'attribut
default_factory
estNone
, lève une exceptionKeyError
avec key comme argument.Si
default_fatory
ne vaut pasNone
, cet attribut est appelé sans argument pour fournir une valeur par défaut pour la key demandée. Cette valeur est insérée dans le dictionnaire avec pour clé key et est renvoyée.Si appeler
default_factory
lève une exception, celle-ci est transmise inchangée.This method is called by the
__getitem__()
method of thedict
class when the requested key is not found; whatever it returns or raises is then returned or raised by__getitem__()
.Note that
__missing__()
is not called for any operations besides__getitem__()
. This means thatget()
will, like normal dictionaries, returnNone
as a default rather than usingdefault_factory
.
Les objets
defaultdict
gèrent la variable d'instance :- default_factory¶
Cet attribut est utilisé par la méthode
__missing__()
; il est initialisé par le premier argument passé au constructeur, s'il est spécifié, sinon parNone
.
Modifié dans la version 3.9: ajout des opérateurs fusion (
|
) et mise-à-jour (|=
) tels que définis dans PEP 584.
Exemples utilisant defaultdict
¶
Utiliser list
comme default_factory
facilite le regroupement d'une séquence de paires clé-valeur en un dictionnaire de listes :
>>> 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])]
Lorsque chaque clé est rencontrée pour la première fois, elle n'est pas encore présente dans le dictionnaire, donc une entrée est automatiquement créée grâce à la fonction default_factory
qui renvoie un objet list
vide. L'opération list.append()
ajoute la valeur à la nouvelle liste. Quand les clés sont à nouveau rencontrées, la recherche se déroule correctement (elle renvoie la liste de cette clé) et l'opération list.append()
ajoute une autre valeur à la liste. Cette technique est plus simple et plus rapide qu'une technique équivalente utilisant dict.setdefault()
:
>>> d = {}
>>> for k, v in s:
... d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Utiliser int
comme default_factory
rend la classe defaultdict
pratique pour le comptage (comme un sac ou multi-ensemble dans d'autres langages) :
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> sorted(d.items())
[('i', 4), ('m', 1), ('p', 2), ('s', 4)]
Quand une lettre est rencontrée pour la première fois, elle n'est pas dans le dictionnaire, donc la fonction default_factory
appelle int()
pour mettre un nouveau compteur à zéro. L'incrémentation augmente ensuite le comptage pour chaque lettre.
La fonction int()
qui retourne toujours zéro est simplement une fonction constante particulière. Un moyen plus flexible et rapide de créer une fonction constante est d'utiliser une fonction lambda qui peut fournir n'importe quelle valeur constante (pas seulement zéro) :
>>> def constant_factory(value):
... return lambda: value
...
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'
Utiliser set
comme default_factory
rend la classe defaultdict
pratique pour créer un dictionnaire d'ensembles :
>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
... d[k].add(v)
...
>>> sorted(d.items())
[('blue', {2, 4}), ('red', {1, 3})]
namedtuple()
: fonction de construction pour n-uplets avec des champs nommés¶
Les n-uplets nommés assignent une signification à chacun de leur élément, ce qui rend le code plus lisible et explicite. Ils peuvent être utilisés partout où les n-uplets natifs sont utilisés, et ils ajoutent la possibilité d'accéder à leurs champs grâce à leur nom au lieu de leur index de position.
- collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)¶
Renvoie une nouvelle sous-classe de
tuple
appelée typename. Elle est utilisée pour créer des objets se comportant comme les n-uplets qui ont des champs accessibles par recherche d'attribut en plus d'être indexables et itérables. Les instances de cette sous-classe possèdent aussi une docstring explicite (avec type_name et les field_names) et une méthode__repr__()
pratique qui liste le contenu du n-uplet au formatnom=valeur
.field_names peut être une séquence de chaînes de caractères telle que
['x', 'y']
ou bien une unique chaîne de caractères où les noms de champs sont séparés par un espace et/ou une virgule, par exemple'x y'
ou'x, y'
.N'importe quel identifiant Python peut être utilisé pour un nom de champ hormis ceux commençant par un tiret bas. Les identifiants valides peuvent contenir des lettres, des chiffres (sauf en première position) et des tirets bas (sauf en première position). Un identifiant ne peut pas être un
keyword
tel queclass
,for
,return
,global
,pass
ouraise
.Si rename vaut
True
, alors les noms de champs invalides sont automatiquement renommés en noms positionnels. Par exemple,['abc', 'def', 'ghi', 'abc']
est converti en['abc, '_1', 'ghi', '_3']
afin d'éliminer le mot-clédef
et le doublon deabc
.defaults peut être
None
ou un iterable de valeurs par défaut. Comme les champs avec une valeur par défaut doivent être définis après les champs sans valeur par défaut, les defaults sont appliqués aux paramètres les plus à droite. Par exemple, si les noms des champs sont['x', 'y', 'z']
et les valeurs par défaut(1, 2)
, alorsx
est un argument obligatoire tandis quey
ety
valent par défaut1
et2
.If module is defined, the
__module__
attribute of the named tuple is set to that value.Les instances de n-uplets nommés n'ont pas de dictionnaires propres, elles sont donc légères et ne requièrent pas plus de mémoire que les n-uplets natifs.
Pour permettre la sérialisation, la classe de n-uplet nommée doit être assignée à une variable qui correspond à typename.
Modifié dans la version 3.1: Gestion de rename.
Modifié dans la version 3.6: Les paramètres verbose et rename deviennent des arguments obligatoirement nommés.
Modifié dans la version 3.6: Ajout du paramètre module.
Modifié dans la version 3.7: Suppression du paramètre verbose et de l'attribut
_source
.Modifié dans la version 3.7: Ajout du paramètre defaults et de l'attribut
_field_defaults
.
>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # instantiate with positional or keyword arguments
>>> p[0] + p[1] # indexable like the plain tuple (11, 22)
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessible by name
33
>>> p # readable __repr__ with a name=value style
Point(x=11, y=22)
Les n-uplets nommés sont particulièrement utiles pour associer des noms de champs à des n-uplets renvoyés par les modules csv
ou sqlite3
:
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
En plus des méthodes héritées de tuple
, les n-uplets nommés implémentent trois méthodes et deux attributs supplémentaires. Pour éviter les conflits avec noms de champs, leurs noms commencent par un tiret bas.
- classmethod somenamedtuple._make(iterable)¶
Méthode de classe qui construit une nouvelle instance à partir d'une séquence ou d'un itérable existant.
>>> t = [11, 22] >>> Point._make(t) Point(x=11, y=22)
- somenamedtuple._asdict()¶
Renvoie un nouveau
dict
qui associe chaque nom de champ à sa valeur correspondante :>>> p = Point(x=11, y=22) >>> p._asdict() {'x': 11, 'y': 22}
Modifié dans la version 3.1: Renvoie un
OrderedDict
au lieu d'undict
natif.Modifié dans la version 3.8: renvoie un
dict
natif plutôt qu'unOrderedDict
. À partir de Python 3.7, les dictionnaires natifs garantissent la préservation de l'ordre. Si les autres fonctionnalités d'OrderedDict
sont nécessaires, la solution préconisée est de convertir le résultat vers le type souhaité :OrderedDict(nt._asdict())
.
- somenamedtuple._replace(**kwargs)¶
Renvoie une nouvelle instance du n-uplet nommé en remplaçant les champs spécifiés par leurs nouvelles valeurs :
>>> p = Point(x=11, y=22) >>> p._replace(x=33) Point(x=33, y=22) >>> for partnum, record in inventory.items(): ... inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
Named tuples are also supported by generic function
copy.replace()
.Modifié dans la version 3.13: Raise
TypeError
instead ofValueError
for invalid keyword arguments.
- somenamedtuple._fields¶
Tuple de chaînes de caractères listant les noms de champs. Pratique pour l'introspection et pour créer de nouveaux types de n-uplets nommés à partir d'existants.
>>> p._fields # view the field names ('x', 'y') >>> Color = namedtuple('Color', 'red green blue') >>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) >>> Pixel(11, 22, 128, 255, 0) Pixel(x=11, y=22, red=128, green=255, blue=0)
- somenamedtuple._field_defaults¶
Dictionnaire qui assigne les valeurs par défaut aux noms des champs.
>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0]) >>> Account._field_defaults {'balance': 0} >>> Account('premium') Account(type='premium', balance=0)
Pour récupérer un champ dont le nom est une chaîne de caractères, utilisez la fonction getattr()
:
>>> getattr(p, 'x')
11
Pour convertir un dictionnaire en n-uplet nommé, utilisez l'opérateur double-étoile (comme expliqué dans Séparation des listes d'arguments) :
>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)
Il est aisé d'ajouter ou de modifier les fonctionnalités des n-uplets nommés grâce à l'héritage puisqu'il s'agit de simples classes. Voici comment ajouter un champ calculé avec une longueur fixe d'affichage :
>>> class Point(namedtuple('Point', ['x', 'y'])):
... __slots__ = ()
... @property
... def hypot(self):
... return (self.x ** 2 + self.y ** 2) ** 0.5
... def __str__(self):
... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
>>> for p in Point(3, 4), Point(14, 5/7):
... print(p)
Point: x= 3.000 y= 4.000 hypot= 5.000
Point: x=14.000 y= 0.714 hypot=14.018
La sous-classe ci-dessus définit __slots__
comme un n-uplet vide. Cela permet de garder une emprunte mémoire faible en empêchant la création de dictionnaire d'instance.
L'héritage n'est pas pertinent pour ajouter de nouveaux champs. Il est préférable de simplement créer un nouveau type de n-uplet nommé avec l'attribut _fields
:
>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))
Les docstrings peuvent être personnalisées en modifiant directement l'attribut __doc__
:
>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'
Modifié dans la version 3.5: La propriété devient éditable.
Voir aussi
Voir
typing.NamedTuple()
pour un moyen d'ajouter des indications de type pour les n-uplets nommés. Cela propose aussi une notation élégante utilisant le mot-cléclass
:class Component(NamedTuple): part_number: int weight: float description: Optional[str] = None
Voir
types.SimpleNamespace()
pour un espace de nommage mutable basé sur un dictionnaire sous-jacent à la place d'un n-uplet.Le module
dataclasses
fournit un décorateur et des fonctions pour ajouter automatiquement des méthodes spéciales générées aux classes définies par l’utilisateur.
Objets OrderedDict
¶
Les dictionnaires ordonnés sont des dictionnaires comme les autres mais possèdent des capacités supplémentaires pour s'ordonner. Ils sont maintenant moins importants puisque la classe native dict
sait se souvenir de l'ordre d'insertion (cette fonctionnalité a été garantie par Python 3.7).
Quelques différences persistent vis-à-vis de dict
:
Les
dict
classiques ont été conçus pour être performants dans les opérations de correspondance. Garder une trace de l'ordre d'insertion était secondaire.Les
OrderedDict
ont été conçus pour être performants dans les opérations de ré-arrangement. L'occupation mémoire, la vitesse de parcours et les performances de mise à jour étaient secondaires.The
OrderedDict
algorithm can handle frequent reordering operations better thandict
. As shown in the recipes below, this makes it suitable for implementing various kinds of LRU caches.Le test d'égalité de
OrderedDict
vérifie si l'ordre correspond.A regular
dict
can emulate the order sensitive equality test withp == q and all(k1 == k2 for k1, k2 in zip(p, q))
.La méthode
popitem()
deOrderedDict
possède une signature différente. Elle accepte un argument optionnel pour spécifier quel élément doit être enlevé.A regular
dict
can emulate OrderedDict'sod.popitem(last=True)
withd.popitem()
which is guaranteed to pop the rightmost (last) item.A regular
dict
can emulate OrderedDict'sod.popitem(last=False)
with(k := next(iter(d)), d.pop(k))
which will return and remove the leftmost (first) item if it exists.OrderedDict
possède une méthodemove_to_end()
pour déplacer efficacement un élément à la fin.A regular
dict
can emulate OrderedDict'sod.move_to_end(k, last=True)
withd[k] = d.pop(k)
which will move the key and its associated value to the rightmost (last) position.A regular
dict
does not have an efficient equivalent for OrderedDict'sod.move_to_end(k, last=False)
which moves the key and its associated value to the leftmost (first) position.Avant Python 3.8,
dict
n'a pas de méthode__reversed__()
.
- class collections.OrderedDict([items])¶
Renvoie une instance d'une sous-classe de
dict
qui possède des méthodes spécialisées pour redéfinir l'ordre du dictionnaire.Ajouté dans la version 3.1.
- popitem(last=True)¶
La méthode
popitem()
pour les dictionnaires ordonnés retire et renvoie une paire(clé, valeur)
. Les paires sont renvoyées comme pour une pile, c'est-à-dire dernier entré, premier sorti (en anglais LIFO) si last vautTrue
. Si last vautFalse
, alors les paires sont renvoyées comme pour une file, c'est-à-dire premier entré, premier sorti (en anglais FIFO).
- move_to_end(key, last=True)¶
Move an existing key to either end of an ordered dictionary. The item is moved to the right end if last is true (the default) or to the beginning if last is false. Raises
KeyError
if the key does not exist:>>> d = OrderedDict.fromkeys('abcde') >>> d.move_to_end('b') >>> ''.join(d) 'acdeb' >>> d.move_to_end('b', last=False) >>> ''.join(d) 'bacde'
Ajouté dans la version 3.2.
En plus des méthodes usuelles des dictionnaires, les dictionnaires ordonnés gèrent l'itération en sens inverse grâce à reversed()
.
Equality tests between OrderedDict
objects are order-sensitive
and are roughly equivalent to list(od1.items())==list(od2.items())
.
Equality tests between OrderedDict
objects and other
Mapping
objects are order-insensitive like regular
dictionaries. This allows OrderedDict
objects to be substituted
anywhere a regular dictionary is used.
Modifié dans la version 3.5: Les vues d'éléments, de clés et de valeurs de OrderedDict
gèrent maintenant l'itération en sens inverse en utilisant reversed()
.
Modifié dans la version 3.6: Suite à l'acceptation de la PEP 468, l'ordre des arguments nommés passés au constructeur et à la méthode update()
de OrderedDict
est conservé.
Modifié dans la version 3.9: ajout des opérateurs fusion (|
) et mise-à-jour (|=
) tels que définis dans PEP 584.
Exemples et cas pratiques utilisant OrderDict
¶
Il est facile de créer une variante de dictionnaire ordonné qui retient l'ordre dans lequel les clés ont été insérées en dernier. Si une nouvelle entrée écrase une existante, la position d'insertion d'origine est modifiée et déplacée à la fin :
class LastUpdatedOrderedDict(OrderedDict):
'Store items in the order the keys were last added'
def __setitem__(self, key, value):
super().__setitem__(key, value)
self.move_to_end(key)
Un OrderedDict
peut aussi être utile pour implémenter des variantes de functools.lru_cache()
:
from collections import OrderedDict
from time import time
class TimeBoundedLRU:
"LRU Cache that invalidates and refreshes old entries."
def __init__(self, func, maxsize=128, maxage=30):
self.cache = OrderedDict() # { args : (timestamp, result)}
self.func = func
self.maxsize = maxsize
self.maxage = maxage
def __call__(self, *args):
if args in self.cache:
self.cache.move_to_end(args)
timestamp, result = self.cache[args]
if time() - timestamp <= self.maxage:
return result
result = self.func(*args)
self.cache[args] = time(), result
if len(self.cache) > self.maxsize:
self.cache.popitem(last=False)
return result
class MultiHitLRUCache:
""" LRU cache that defers caching a result until
it has been requested multiple times.
To avoid flushing the LRU cache with one-time requests,
we don't cache until a request has been made more than once.
"""
def __init__(self, func, maxsize=128, maxrequests=4096, cache_after=1):
self.requests = OrderedDict() # { uncached_key : request_count }
self.cache = OrderedDict() # { cached_key : function_result }
self.func = func
self.maxrequests = maxrequests # max number of uncached requests
self.maxsize = maxsize # max number of stored return values
self.cache_after = cache_after
def __call__(self, *args):
if args in self.cache:
self.cache.move_to_end(args)
return self.cache[args]
result = self.func(*args)
self.requests[args] = self.requests.get(args, 0) + 1
if self.requests[args] <= self.cache_after:
self.requests.move_to_end(args)
if len(self.requests) > self.maxrequests:
self.requests.popitem(last=False)
else:
self.requests.pop(args, None)
self.cache[args] = result
if len(self.cache) > self.maxsize:
self.cache.popitem(last=False)
return result
Objets UserDict
¶
La classe UserDict
se comporte comme une surcouche autour des dictionnaires. L'utilité de cette classe est réduite, car on peut maintenant hériter directement de dict
. Cependant, il peut être plus facile de travailler avec celle-ci, car le dictionnaire sous-jacent est accessible comme attribut.
- class collections.UserDict([initialdata])¶
Classe simulant un dictionnaire. Les instances de
UserDict
possèdent un attributdata
où est stocké leur contenu sous forme de dictionnaire natif. Si initialdata est spécifié, alorsdata
est initialisé avec son contenu. Remarquez qu'une référence vers initialdata n'est pas conservée, ce qui permet de l'utiliser pour d'autres tâches.En plus de gérer les méthodes et opérations des dictionnaires, les instances de
UserDict
fournissent l'attribut suivant :
Objets UserList
¶
Cette classe agit comme une surcouche autour des objets list
. C'est une classe mère utile pour vos classes listes-compatibles qui peuvent en hériter et surcharger les méthodes existantes ou en ajouter de nouvelles. Ainsi, on peut ajouter de nouveaux comportements aux listes.
L'utilité de cette classe a été partiellement réduite par la possibilité d'hériter directement de list
. Cependant, il peut être plus facile de travailler avec cette classe, car la liste sous-jacente est accessible via un attribut.
- class collections.UserList([list])¶
Classe simulant une liste. Les instances de
UserList
possèdent un attributUserList
où est stocké leur contenu sous forme de liste native. Il est initialement une copie de list, ou[]
par défaut. list peut être un itérable, par exemple une liste native ou un objetUserList
.En plus de gérer les méthodes et opérations des séquences mutables, les instances de
UserList
possèdent l'attribut suivant :
Prérequis pour l'héritage : Les sous-classes de UserList
doivent implémenter un constructeur qui peut être appelé avec zéro ou un argument. Les opérations sur les listes qui renvoient une nouvelle séquence essayent de créer une instance de la classe courante. C'est pour cela que le constructeur doit pouvoir être appelé avec un unique paramètre, un objet séquence utilisé comme source de données.
Si une classe fille ne remplit pas cette condition, toutes les méthodes spéciales gérées par cette classe devront être implémentées à nouveau. Merci de consulter les sources pour obtenir des informations sur les méthodes qui doivent être fournies dans ce cas.
Objets UserString
¶
La classe UserString
agit comme une surcouche autour des objets str
. L'utilité de cette classe a été partiellement réduite par la possibilité d'hériter directement de str
. Cependant, il peut être plus facile de travailler avec cette classe, car la chaîne de caractère sous-jacente est accessible via un attribut.
- class collections.UserString(seq)¶
Classe simulant une chaîne de caractères. Les instances de
UserString
possèdent un attributdata
où est stocké leur contenu sous forme de chaîne de caractères native. Le contenu de l'instance est initialement une copie de seq, qui peut être n'importe quel objet convertible en chaîne de caractère avec la fonction nativestr()
.En plus de gérer les méthodes et opérations sur les chaînes de caractères, les instances de
UserString
possèdent l'attribut suivant :- data¶
Un objet
str
natif utilisé pour stocker le contenu de la classeUserString
.
Modifié dans la version 3.5: Nouvelles méthodes
__getnewargs__
,__rmod__
,casefold
,format_map
,isprintable
etmaketrans
.