diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index d847d6b7922..ca2f1167cc8 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -100,6 +100,21 @@ The class can be used to simulate nested scopes and is useful in templating. :func:`super` function. A reference to ``d.parents`` is equivalent to: ``ChainMap(*d.maps[1:])``. + Note, the iteration order of a :class:`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'] + + This gives the same ordering as a series of :meth:`dict.update` calls + starting with the last mapping:: + + >>> combined = baseline.copy() + >>> combined.update(adjustments) + >>> list(combined) + ['music', 'art', 'opera'] .. seealso:: diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index 74372d28ed0..2d5a2661b68 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -113,6 +113,20 @@ class TestChainMap(unittest.TestCase): self.assertEqual(f['b'], 5) # find first in chain self.assertEqual(f.parents['b'], 2) # look beyond maps[0] + def test_ordering(self): + # Combined order matches a series of dict updates from last to first. + # This test relies on the ordering of the underlying dicts. + + baseline = {'music': 'bach', 'art': 'rembrandt'} + adjustments = {'art': 'van gogh', 'opera': 'carmen'} + + cm = ChainMap(adjustments, baseline) + + combined = baseline.copy() + combined.update(adjustments) + + self.assertEqual(list(combined.items()), list(cm.items())) + def test_constructor(self): self.assertEqual(ChainMap().maps, [{}]) # no-args --> one new dict self.assertEqual(ChainMap({1:2}).maps, [{1:2}]) # 1 arg --> list