8.3. "collections" — High-performance container datatypes
*********************************************************

Nouveau dans la version 2.4.

**Source code:** Lib/collections.py and Lib/_abcoll.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".

+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "namedtuple()"        | fonction permettant de créer des sous-classes de "tuple" avec des    | Nouveau dans la version     |
|                       | champs nommés                                                        | 2.6.                        |
+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "deque"               | conteneur se comportant comme une liste avec des ajouts et retraits  | Nouveau dans la version     |
|                       | rapides à chaque extrémité                                           | 2.4.                        |
+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "Counter"             | sous-classe de "dict" pour compter des objets hachables              | Nouveau dans la version     |
|                       |                                                                      | 2.7.                        |
+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "OrderedDict"         | sous-classe de "dict" qui garde en mémoire l’ordre dans lequel les   | Nouveau dans la version     |
|                       | entrées ont été ajoutées                                             | 2.7.                        |
+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "defaultdict"         | sous-classe de "dict" qui appelle une fonction de fabrication en cas | Nouveau dans la version     |
|                       | de valeur manquante                                                  | 2.5.                        |
+-----------------------+----------------------------------------------------------------------+-----------------------------+

In addition to the concrete container classes, the collections module
provides abstract base classes that can be used to test whether a
class provides a particular interface, for example, whether it is
hashable or a mapping.


8.3.1. 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])

   La classe "Counter" est une sous-classe de "dict" qui permet le
   dénombrement d’objets hachables. Il s’agit d’une collection non
   ordonnée dans laquelle les éléments sont stockés comme des clés de
   dictionnaire et leurs nombres d’occurrences respectifs comme leurs
   valeurs. Ceux-ci peuvent être des entiers relatifs (positifs,
   négatifs ou nuls). La classe "Counter" est similaire aux sacs ou
   aux multiensembles dans d’autres langages.

   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

   Nouveau dans la version 2.7.

   En plus des méthodes disponibles pour tous les dictionnaires, les
   objets compteurs gèrent trois méthodes supplémentaires :

   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 un ordre arbitraire. 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)
      >>> list(c.elements())
      ['a', 'a', 'a', 'a', 'b', 'b']

   most_common([n])

      Return a list of the *n* most common elements and their counts
      from the most common to the least.  If *n* is omitted or "None",
      "most_common()" returns *all* elements in the counter. Elements
      with equal counts are ordered arbitrarily:

      >>> Counter('abracadabra').most_common(3)
      [('a', 5), ('r', 2), ('b', 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})

   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.

   fromkeys(iterable)

      Cette méthode de classe n’est pas implémentée pour les objets
      "Counter".

   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)".

Opérations usuelles sur les objets "Counter" :

   sum(c.values())                 # 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()                       # convert to a list of (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 += Counter()                  # remove zero and negative counts

Quelques opérations mathématiques sont fournies pour combiner des
objets "Counter" afin de créer des multiensembles (des compteurs dont
les dénombrements des éléments sont strictement supérieurs à zéro).
Les additions et soustractions combinent les compteurs en ajoutant ou
retranchant les nombres d’occurrences des éléments correspondants. Les
intersections et unions renvoient les minimums et maximums des
comptages correspondants. Chaque opération peut accepter des entrées
avec des comptages relatifs, mais la sortie exclut les résultats avec
des comptages négatifs ou nuls.

>>> 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})

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.

  * The "most_common()" method requires only that the values be
    orderable.

  * For in-place operations such as "c[key] += 1", the value type
    need only support addition and subtraction.  So fractions, floats,
    and decimals would work and negative values are supported.  The
    same is also true for "update()" and "subtract()" which allow
    negative and zero values for both inputs and outputs.

  * 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.

  * The "elements()" method requires integer counts.  It ignores
    zero and negative counts.

Voir aussi:

  * Counter class adapted for Python 2.5 and an early Bag recipe for
    Python 2.4.

  * Bag class in 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*.

  * To enumerate all distinct multisets of a given size over a given
    set of elements, see "itertools.combinations_with_replacement()".

       map(Counter, combinations_with_replacement(“ABC”, 2)) –> AA AB
       AC BB BC CC


8.3.2. 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.

   Les *deques* sont une généralisation des piles et des files
   (*deque* se prononce « *dèque* » et est l’abréviation de l’anglais
   *double-ended queue*) : il est possible d’ajouter et retirer des
   éléments par les deux bouts des *deques*. Celles-ci gèrent des
   ajouts et des retraits utilisables par de multiples fils
   d’exécution (*thread-safe*) et efficients du point de vue de la
   mémoire des deux côtés de la *deque*, avec approximativement la
   même performance en *O(1)* dans les deux sens.

   Bien que les les objets "list" gèrent des opérations similaires,
   ils sont optimisés pour des opérations qui ne changent pas la
   taille de la liste. Les opérations "pop(0)" et "insert(0, v)" qui
   changent la taille et la position de la représentation des données
   sous-jacentes entraînent des coûts de déplacement de mémoire en
   *O(n)*.

   Nouveau dans la version 2.4.

   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 similaire
   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.

   Modifié dans la version 2.6: Added *maxlen* parameter.

   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.

   count(x)

      Compte le nombre d’éléments de la *deque* égaux à *x*.

      Nouveau dans la version 2.7.

   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.

   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)

      Remove the first occurrence of *value*.  If not found, raises a
      "ValueError".

      Nouveau dans la version 2.5.

   reverse()

      Inverse le sens des éléments de la *deque* sans créer de copie
      et renvoie "None".

      Nouveau dans la version 2.7.

   rotate(n=1)

      Rotate the deque *n* steps to the right.  If *n* is negative,
      rotate to the left.

      When the deque is not empty, rotating one step to the right is
      equivalent to "d.appendleft(d.pop())", and rotating one step to
      the left is equivalent to "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.

      Nouveau dans la version 2.7.

En plus des méthodes précédentes, les *deques* gèrent l’itération, la
sérialisation, "len(d)", "reversed(d)", "copy.copy(d)",
"copy.deepcopy(d)", le test d’appartenance avec l’opérateur "in", et
les références en indice comme "d[-1]". L’accès par indice est en
*O(1)* aux extrémités mais en *O(n)* au milieu. Pour des accès
aléatoires rapides, il est préférable d’utiliser des listes.

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'])


8.3.2.1. 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'
       return deque(open(filename), 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
       # http://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 / float(n)

The "rotate()" method provides a way to implement "deque" slicing and
deletion.  For example, a pure Python implementation of "del d[n]"
relies on the "rotate()" method to position elements to be popped:

   def delete_nth(d, n):
       d.rotate(-n)
       d.popleft()
       d.rotate(n)

To implement "deque" slicing, use a similar approach applying
"rotate()" to bring a target element to the left side of the deque.
Remove old entries with "popleft()", add new entries with "extend()",
and then reverse the rotation. With minor variations on that approach,
it is easy to implement Forth style stack manipulations such as "dup",
"drop", "swap", "over", "pick", "rot", and "roll".


8.3.3. Objets "defaultdict"
===========================

class collections.defaultdict([default_factory[, ...]])

   Renvoie un nouvel objet qui se comporte comme un dictionnaire.
   "defaultdic" est une sous-classe de la la classe native "dict".
   Elle surcharge une méthode et ajoute une variable d’instance
   modifiable. Les autres fonctionnalités sont les mêmes que celles
   des objets "dict" 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
   ou "None", sa valeur par défaut. Tous les autres arguments sont
   traités comme si on les passait au constructeur de "dict", y
   compris les arguments nommés.

   Nouveau dans la version 2.5.

   En plus des opérations usuelles de "dict", les objets "defaultdict"
   gèrent les méthodes supplémentaires suivantes :

   __missing__(key)

      Si l’attribut "default_factory" est "None", lève une exception
      "KeyError" avec *key* comme argument.

      Si "default_fatory`" ne vaut pas "None", 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.

      Cette méthode est appelée par la méthode "__getitem__()" de la
      classe "dict" lorsque la clé demandée n’est pas trouvée. Ce
      qu’elle renvoie ou lève est alors renvoyé ou levé par
      "__getitem__()".

      Remarquez que "__missing__()" n’est *pas* appelée pour les
      opérations autres que "__getitem__()". Cela signifie que "get()"
      renvoie "None" comme les dictionnaires natifs dans les cas
      triviaux et n’utilise pas "default_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 par "None".


8.3.3.1. Exemples utilisant "defaultdict"
-----------------------------------------

Using "list" as the "default_factory", it is easy to group a sequence
of key-value pairs into a dictionary of lists:

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

When each key is encountered for the first time, it is not already in
the mapping; so an entry is automatically created using the
"default_factory" function which returns an empty "list".  The
"list.append()" operation then attaches the value to the new list.
When keys are encountered again, the look-up proceeds normally
(returning the list for that key) and the "list.append()" operation
adds another value to the list. This technique is simpler and faster
than an equivalent technique using "dict.setdefault()":

>>> d = {}
>>> for k, v in s:
...     d.setdefault(k, []).append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

Setting the "default_factory" to "int" makes the "defaultdict" useful
for counting (like a bag or multiset in other languages):

>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
...     d[k] += 1
...
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]

When a letter is first encountered, it is missing from the mapping, so
the "default_factory" function calls "int()" to supply a default count
of zero.  The increment operation then builds up the count for each
letter.

The function "int()" which always returns zero is just a special case
of constant functions.  A faster and more flexible way to create
constant functions is to use "itertools.repeat()" which can supply any
constant value (not just zero):

>>> def constant_factory(value):
...     return itertools.repeat(value).next
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'

Setting the "default_factory" to "set" makes the "defaultdict" useful
for building a dictionary of sets:

>>> 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)
...
>>> d.items()
[('blue', set([2, 4])), ('red', set([1, 3]))]


8.3.4. "namedtuple()": fonction de construction pour *n-uplets* (*tuples*) avec des champs nommés
=================================================================================================

Les tuples 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 tuples 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[, verbose=False][, rename=False])

   Renvoie une nouvelle sous-classe de "tuple" appelée *typename*.
   Elle est utilisée pour créer des objets se comportant comme les
   *tuples* 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 tuple au format "nom=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'".

   Any valid Python identifier may be used for a fieldname except for
   names starting with an underscore.  Valid identifiers consist of
   letters, digits, and underscores but do not start with a digit or
   underscore and cannot be a "keyword" such as *class*, *for*,
   *return*, *global*, *pass*, *print*, or *raise*.

   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 de "abc".

   If *verbose* is true, the class definition is printed just before
   being built.

   Les instances de tuples 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 tuples natifs.

   Nouveau dans la version 2.6.

   Modifié dans la version 2.7: added support for *rename*.

Exemple :

   >>> Point = namedtuple('Point', ['x', 'y'], verbose=True)
   class Point(tuple):
       'Point(x, y)'

       __slots__ = ()

       _fields = ('x', 'y')

       def __new__(_cls, x, y):
           'Create new instance of Point(x, y)'
           return _tuple.__new__(_cls, (x, y))

       @classmethod
       def _make(cls, iterable, new=tuple.__new__, len=len):
           'Make a new Point object from a sequence or iterable'
           result = new(cls, iterable)
           if len(result) != 2:
               raise TypeError('Expected 2 arguments, got %d' % len(result))
           return result

       def __repr__(self):
           'Return a nicely formatted representation string'
           return 'Point(x=%r, y=%r)' % self

       def _asdict(self):
           'Return a new OrderedDict which maps field names to their values'
           return OrderedDict(zip(self._fields, self))

       def _replace(_self, **kwds):
           'Return a new Point object replacing specified fields with new values'
           result = _self._make(map(kwds.pop, ('x', 'y'), _self))
           if kwds:
               raise ValueError('Got unexpected field names: %r' % kwds.keys())
           return result

       def __getnewargs__(self):
           'Return self as a plain tuple.  Used by copy and pickle.'
           return tuple(self)

       __dict__ = _property(_asdict)

       def __getstate__(self):
           'Exclude the OrderedDict from pickling'
           pass

       x = _property(_itemgetter(0), doc='Alias for field number 0')

       y = _property(_itemgetter(1), doc='Alias for field number 1')



   >>> 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 tuples nommés sont particulièrement utiles pour associer des noms
de champs à des tuples 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

In addition to the methods inherited from tuples, named tuples support
three additional methods and one attribute.  To prevent conflicts with
field names, the method and attribute names start with an underscore.

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()

   Return a new "OrderedDict" which maps field names to their
   corresponding values:

      >>> p = Point(x=11, y=22)
      >>> p._asdict()
      OrderedDict([('x', 11), ('y', 22)])

   Modifié dans la version 2.7: Renvoie un "OrderedDict" au lieu d’un
   "dict" natif.

somenamedtuple._replace(**kwargs)

   Renvoie une nouvelle instance du tuple 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())

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 tuples
   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)

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 tuple 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 tuples
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 tuple vide. Cela
permet de garder une emprunte mémoire faible en empêchant la création
de dictionnaire d’instance.

Subclassing is not useful for adding new, stored fields.  Instead,
simply create a new named tuple type from the "_fields" attribute:

>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))

Default values can be implemented by using "_replace()" to customize a
prototype instance:

>>> Account = namedtuple('Account', 'owner balance transaction_count')
>>> default_account = Account('<owner name>', 0.0, 0)
>>> johns_account = default_account._replace(owner='John')

Enumerated constants can be implemented with named tuples, but it is
simpler and more efficient to use a simple class declaration:

>>> Status = namedtuple('Status', 'open pending closed')._make(range(3))
>>> Status.open, Status.pending, Status.closed
(0, 1, 2)
>>> class Status:
...     open, pending, closed = range(3)

Voir aussi: Named tuple recipe adapted for Python 2.4.


8.3.5. Objets "OrderedDict"
===========================

En plus de se comporter comme des dictionnaires natifs, les
dictionnaires ordonnés mémorisent l’ordre dans lequel les éléments ont
été insérés. Quand on itère sur un dictionnaire ordonné, les éléments
sont renvoyés dans l’ordre d’insertion des clés.

class collections.OrderedDict([items])

   Renvoie une instance d’une sous-classe de "dict" qui gère les
   méthodes usuelles de "dict". Un objet *OrderedDict* est un
   dictionnaire qui mémorise l’ordre d’insertion des clés. Si une
   nouvelle entrée en écrase une autre, sa position reste inchangé. Si
   une entrée est supprimée puis réinsérée, elle est placée en
   dernière position.

   Nouveau dans la version 2.7.

OrderedDict.popitem(last=True)

   The "popitem()" method for ordered dictionaries returns and removes
   a (key, value) pair.  The pairs are returned in LIFO order if
   *last* is true or FIFO order if false.

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 implemented as "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.

The "OrderedDict" constructor and "update()" method both accept
keyword arguments, but their order is lost because Python’s function
call semantics pass-in keyword arguments using a regular unordered
dictionary.

Voir aussi: Equivalent OrderedDict recipe that runs on Python 2.4 or
  later.


8.3.5.1. Exemples et cas pratiques utilisant "OrderDict"
--------------------------------------------------------

Puisqu’un dictionnaire ordonné mémorise l’ordre d’insertion de ses
éléments, il peut être utilisé conjointement avec un classement pour
créer un dictionnaire trié :

   >>> # regular unsorted dictionary
   >>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}

   >>> # dictionary sorted by key
   >>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
   OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

   >>> # dictionary sorted by value
   >>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
   OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

   >>> # dictionary sorted by length of the key string
   >>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
   OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

Les nouveaux dictionnaires triés gardent leur classement quand des
entrées sont supprimées, mais si de nouvelles clés sont ajoutées,
celles-ci sont ajoutée à la fin et le classement est perdu.

Il est également 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):
           if key in self:
               del self[key]
           OrderedDict.__setitem__(self, key, value)

Un dictionnaire ordonné peut être combiné avec la classe "Counter"
afin de mémoriser l’ordre dans lequel les éléments ont été ajoutés
pour la première fois :

   class OrderedCounter(Counter, OrderedDict):
        'Counter that remembers the order elements are first encountered'

        def __repr__(self):
            return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

        def __reduce__(self):
            return self.__class__, (OrderedDict(self),)


8.3.6. Classes de base abstraites de collections
================================================

Le module collections apporte les *ABC* suivantes :

+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| ABC                       | Hérite de             | Méthodes abstraites    | Méthodes *mixin*                                     |
+===========================+=======================+========================+======================================================+
| "Container"               |                       | "__contains__"         |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Hashable"                |                       | "__hash__"             |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Iterable"                |                       | "__iter__"             |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Iterator"                | "Iterable"            | "next"                 | "__iter__"                                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Sized"                   |                       | "__len__"              |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Callable"                |                       | "__call__"             |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Sequence"                | "Sized", "Iterable",  | "__getitem__",         | "__contains__", "__iter__", "__reversed__", "index"  |
|                           | "Container"           | "__len__"              | et "count"                                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "MutableSequence"         | "Sequence"            | "__getitem__",         | Méthodes héritées de "Sequence", et "append",        |
|                           |                       | "__setitem__",         | "reverse", "extend", "pop", "remove" et "__iadd__"   |
|                           |                       | "__delitem__",         |                                                      |
|                           |                       | "__len__", "insert"    |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Set"                     | "Sized", "Iterable",  | "__contains__",        | "__le__", "__lt__", "__eq__", "__ne__", "__gt__",    |
|                           | "Container"           | "__iter__", "__len__"  | "__ge__", "__and__", "__or__", "__sub__", "__xor__"  |
|                           |                       |                        | et "isdisjoint"                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "MutableSet"              | "Set"                 | "__contains__",        | Méthodes héritées de "Set", et "clear", "pop",       |
|                           |                       | "__iter__", "__len__", | "remove", "__ior__", "__iand__", "__ixor__" et       |
|                           |                       | "add", "discard"       | "__isub__"                                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Mapping"                 | "Sized", "Iterable",  | "__getitem__",         | "__contains__", "keys", "items", "values", "get",    |
|                           | "Container"           | "__iter__", "__len__"  | "__eq__" et "__ne__"                                 |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "MutableMapping"          | "Mapping"             | "__getitem__",         | Méthodes héritées de "Mapping", et "pop", "popitem", |
|                           |                       | "__setitem__",         | "clear", "update" et "setdefault"                    |
|                           |                       | "__delitem__",         |                                                      |
|                           |                       | "__iter__", "__len__"  |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "MappingView"             | "Sized"               |                        | "__len__"                                            |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "ItemsView"               | "MappingView", "Set"  |                        | "__contains__", "__iter__"                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "KeysView"                | "MappingView", "Set"  |                        | "__contains__", "__iter__"                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "ValuesView"              | "MappingView"         |                        | "__contains__", "__iter__"                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+

class collections.Container
class collections.Hashable
class collections.Sized
class collections.Callable

   ABC pour les classes qui définissent respectivement les méthodes
   "__contains__()", "__hash__()", "__len__()" et "__call__()".

class collections.Iterable

   ABC for classes that provide the "__iter__()" method. See also the
   definition of *iterable*.

class collections.Iterator

   ABC for classes that provide the "__iter__()" and "next()" methods.
   See also the definition of *iterator*.

class collections.Sequence
class collections.MutableSequence

   ABC pour les *séquences* immuables et muables.

class collections.Set
class collections.MutableSet

   ABC pour les ensembles immuables et muables.

class collections.Mapping
class collections.MutableMapping

   ABC pour les *tables de correspondances* immuables et muables.

class collections.MappingView
class collections.ItemsView
class collections.KeysView
class collections.ValuesView

   ABC pour les *vues* de *mappings* (tableaux de correspondances),
   d’éléments, de clés et de valeurs.

Ces ABC permettent de demander à des classes ou à des instances si
elles fournissent des fonctionnalités particulières, par exemple

   size = None
   if isinstance(myvar, collections.Sized):
       size = len(myvar)

Several of the ABCs are also useful as mixins that make it easier to
develop classes supporting container APIs.  For example, to write a
class supporting the full "Set" API, it only necessary to supply the
three underlying abstract methods: "__contains__()", "__iter__()", and
"__len__()". The ABC supplies the remaining methods such as
"__and__()" and "isdisjoint()"

   class ListBasedSet(collections.Set):
        ''' Alternate set implementation favoring space over speed
            and not requiring the set elements to be hashable. '''
        def __init__(self, iterable):
            self.elements = lst = []
            for value in iterable:
                if value not in lst:
                    lst.append(value)

        def __iter__(self):
            return iter(self.elements)

        def __contains__(self, value):
            return value in self.elements

        def __len__(self):
            return len(self.elements)

   s1 = ListBasedSet('abcdef')
   s2 = ListBasedSet('defghi')
   overlap = s1 & s2            # The __and__() method is supported automatically

Notes à propos de l’utilisation de "Set" et "MutableSet" comme *mixin*
:

1. Comme une partie des opérations sur les ensembles créent de
   nouveaux ensembles, les méthodes *mixins* par défaut ont besoin
   d’un moyen de créer de nouvelles instances à partir d’un itérable.
   Le constructeur de classe est supposé avoir une signature de la
   forme "ClassName(iterable)". Cette supposition est faite par une
   méthode de classe interne appelée "_from_iterable()" qui appelle
   "cls(iterable)" pour construire un nouvel ensemble. Si le "Set"
   *mixin* est utilisé dans une classe avec un constructeur de
   signature différente, vous devrez surcharger "_from_iterable()"
   avec une méthode de classe qui peut construire de nouvelles
   instances à partir d’un argument itérable.

2. Pour surcharger les comparaisons (a priori pour la rapidité,
   puisque la sémantique est fixe), il faut redéfinir "__le__()" et
   "__ge__()", puis les autres opérations seront automatiquement
   adaptées.

3. La classe *mixin* "Set" apporte une méthode "_hash()" pour
   calculer une valeur de hachage pour l’ensemble ; cependant
   "__hash__()" n’est pas défini car tous les ensembles ne sont pas
   hachables ou immuables. Pour rendre un ensemble hachable en
   utilisant les *mixins*, héritez de "Set()" et de "Hashable()", puis
   définissez "__hash__ = Set._hash".

Voir aussi:

  * OrderedSet recipe pour un exemple construit sur "MutableSet".

  * Pour plus d’informations à propos des ABC, voir le module "abc"
    et la **PEP 3119**.
