Commit 49fd6dd8 authored by Raymond Hettinger's avatar Raymond Hettinger Committed by GitHub

bpo-36059: Update OrderedDict() docs to reflect that regular dicts are now ordered (GH-11966)

parent 11fa0e48
...@@ -887,7 +887,7 @@ field names, the method and attribute names start with an underscore. ...@@ -887,7 +887,7 @@ field names, the method and attribute names start with an underscore.
.. method:: somenamedtuple._asdict() .. method:: somenamedtuple._asdict()
Return a new :class:`OrderedDict` which maps field names to their corresponding Return a new :class:`dict` which maps field names to their corresponding
values: values:
.. doctest:: .. doctest::
...@@ -1024,17 +1024,41 @@ customize a prototype instance: ...@@ -1024,17 +1024,41 @@ customize a prototype instance:
:class:`OrderedDict` objects :class:`OrderedDict` objects
---------------------------- ----------------------------
Ordered dictionaries are just like regular dictionaries but they remember the Ordered dictionaries are just like regular dictionaries but have some extra
order that items were inserted. When iterating over an ordered dictionary, capabilities relating to ordering operations. They have become less
the items are returned in the order their keys were first added. important now that the built-in :class:`dict` class gained the ability
to remember insertion order (this new behavior became guaranteed in
Python 3.7).
Some differences from :class:`dict` still remain:
* The regular :class:`dict` was designed to be very good at mapping
operations. Tracking insertion order was secondary.
* The :class:`OrderedDict` was designed to be good at reordering operations.
Space efficiency, iteration speed, and the performance of update
operations were secondary.
* Algorithmically, :class:`OrderedDict` can handle frequent reordering
operations better than :class:`dict`. This makes it suitable for tracking
recent accesses (for example in an `LRU cache
<https://medium.com/@krishankantsinghal/my-first-blog-on-medium-583159139237>`_).
* The equality operation for :class:`OrderedDict` checks for matching order.
* The :meth:`popitem` method of :class:`OrderedDict` has a different
signature. It accepts an optional argument to specify which item is popped.
* :class:`OrderedDict` has a :meth:`move_to_end` method to
efficiently reposition an element to an endpoint.
* Until Python 3.8, :class:`dict` lacked a :meth:`__reversed__` method.
.. class:: OrderedDict([items]) .. class:: OrderedDict([items])
Return an instance of a dict subclass, supporting the usual :class:`dict` Return an instance of a :class:`dict` subclass that has methods
methods. An *OrderedDict* is a dict that remembers the order that keys specialized for rearranging dictionary order.
were first inserted. If a new entry overwrites an existing entry, the
original insertion position is left unchanged. Deleting an entry and
reinserting it will move it to the end.
.. versionadded:: 3.1 .. versionadded:: 3.1
...@@ -1084,29 +1108,7 @@ anywhere a regular dictionary is used. ...@@ -1084,29 +1108,7 @@ anywhere a regular dictionary is used.
:class:`OrderedDict` Examples and Recipes :class:`OrderedDict` Examples and Recipes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Since an ordered dictionary remembers its insertion order, it can be used It is straightforward to create an ordered dictionary variant
in conjunction with sorting to make a sorted dictionary::
>>> # 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)])
The new sorted dictionaries maintain their sort order when entries
are deleted. But when new keys are added, the keys are appended
to the end and the sort is not maintained.
It is also straight-forward to create an ordered dictionary variant
that remembers the order the keys were *last* inserted. that remembers the order the keys were *last* inserted.
If a new entry overwrites an existing entry, the If a new entry overwrites an existing entry, the
original insertion position is changed and moved to the end:: original insertion position is changed and moved to the end::
...@@ -1115,21 +1117,29 @@ original insertion position is changed and moved to the end:: ...@@ -1115,21 +1117,29 @@ original insertion position is changed and moved to the end::
'Store items in the order the keys were last added' 'Store items in the order the keys were last added'
def __setitem__(self, key, value): def __setitem__(self, key, value):
if key in self: super().__setitem__(key, value)
del self[key] super().move_to_end(key)
OrderedDict.__setitem__(self, key, value)
An ordered dictionary can be combined with the :class:`Counter` class An :class:`OrderedDict` would also be useful for implementing
so that the counter remembers the order elements are first encountered:: variants of :func:`functools.lru_cache`::
class OrderedCounter(Counter, OrderedDict): class LRU(OrderedDict):
'Counter that remembers the order elements are first encountered' 'Limit size, evicting the least recently looked-up key when full'
def __repr__(self): def __init__(self, maxsize=128, *args, **kwds):
return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) self.maxsize = maxsize
super().__init__(*args, **kwds)
def __reduce__(self): def __getitem__(self, key):
return self.__class__, (OrderedDict(self),) value = super().__getitem__(key)
self.move_to_end(key)
return value
def __setitem__(self, key, value):
super().__setitem__(key, value)
if len(self) > self.maxsize:
oldest = next(iter(self))
del self[oldest]
:class:`UserDict` objects :class:`UserDict` objects
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment