[Python-checkins] r88628 - in python/branches/py3k: Doc/library/collections.rst Lib/collections/__init__.py Lib/configparser.py Lib/string.py Lib/test/test_collections.py Misc/NEWS

raymond.hettinger python-checkins at python.org
Sat Feb 26 02:02:51 CET 2011


Author: raymond.hettinger
Date: Sat Feb 26 02:02:51 2011
New Revision: 88628

Log:
Issue #11297: Add collections.ChainMap()



Modified:
   python/branches/py3k/Doc/library/collections.rst
   python/branches/py3k/Lib/collections/__init__.py
   python/branches/py3k/Lib/configparser.py
   python/branches/py3k/Lib/string.py
   python/branches/py3k/Lib/test/test_collections.py
   python/branches/py3k/Misc/NEWS

Modified: python/branches/py3k/Doc/library/collections.rst
==============================================================================
--- python/branches/py3k/Doc/library/collections.rst	(original)
+++ python/branches/py3k/Doc/library/collections.rst	Sat Feb 26 02:02:51 2011
@@ -23,6 +23,7 @@
 =====================   ====================================================================
 :func:`namedtuple`      factory function for creating tuple subclasses with named fields
 :class:`deque`          list-like container with fast appends and pops on either end
+:class:`ChainMap`       dict-like class for creating a single view of multiple mappings
 :class:`Counter`        dict subclass for counting hashable objects
 :class:`OrderedDict`    dict subclass that remembers the order entries were added
 :class:`defaultdict`    dict subclass that calls a factory function to supply missing values
@@ -37,6 +38,119 @@
    as well.
 
 
+:class:`ChainMap` objects
+-------------------------
+
+A :class:`ChainMap` class is provided for quickly linking a number of mappings
+so they can be treated as a single unit.  It is often much faster than creating
+a new dictionary and running multiple :meth:`~dict.update` calls.
+
+The class can be used to simulate nested scopes and is useful in templating.
+
+.. class:: ChainMap(*maps)
+
+   A :class:`ChainMap` groups multiple dicts or other mappings together to
+   create a single, updateable view.  If no *maps* are specified, a single empty
+   dictionary is provided so that a new chain always has at least one mapping.
+
+   The underlying mappings are stored in a list.  That list is public and can
+   accessed or updated using the *maps* attribute.  There is no other state.
+
+   Lookups search the underlying mappings successively until a key is found.  In
+   contrast, writes, updates, and deletions only operate on the first mapping.
+
+   A class:`ChainMap` incorporates the underlying mappings by reference.  So, if
+   one of the underlying mappings gets updated, those changes will be reflected
+   in class:`ChainMap`.
+
+   All of the usual dictionary methods are supported.  In addition, there is a
+   *maps* attribute, a method for creating new subcontexts, and a property for
+   accessing all but the first mapping:
+
+   .. attribute:: maps
+
+      A user updateable list of mappings.  The list is ordered from
+      first-searched to last-searched.  It is the only stored state and can
+      modified to change which mappings are searched.  The list should
+      always contain at least one mapping.
+
+   .. method:: new_child()
+
+      Returns a new :class:`ChainMap` containing a new :class:`dict` followed by
+      all of the maps in the current instance.  A call to ``d.new_child()`` is
+      equivalent to: ``ChainMap({}, *d.maps)``.  This method is used for
+      creating subcontexts that can be updated without altering values in any
+      of the parent mappings.
+
+   .. attribute:: parents()
+
+      Returns a new :class:`ChainMap` containing all of the maps in the current
+      instance except the first one.  This is useful for skipping the first map
+      in the search.  The use-cases are similar to those for the
+      :keyword:`nonlocal` keyword used in :term:`nested scopes <nested scope>`.
+      The use-cases also parallel those for the builtin :func:`super` function.
+      A reference to  ``d.parents`` is equivalent to: ``ChainMap(*d.maps[1:])``.
+
+  .. versionadded:: 3.3
+
+  Example of simulating Python's internal lookup chain::
+
+     import __builtin__
+     pylookup = ChainMap(locals(), globals(), vars(__builtin__))
+
+  Example of letting user specified values take precedence over environment
+  variables which in turn take precedence over default values::
+
+     import os, argparse
+     defaults = {'color': 'red', 'user': guest}
+     parser = argparse.ArgumentParser()
+     parser.add_argument('-u', '--user')
+     parser.add_argument('-c', '--color')
+     user_specified = vars(parser.parse_args())
+     combined = ChainMap(user_specified, os.environ, defaults)
+
+  Example patterns for using the :class:`ChainMap` class to simulate nested
+  contexts::
+
+    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']                  Get first key in the chain of contexts
+    d['x'] = 1              Set value in current context
+    del['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
+
+  .. seealso::
+
+     * The `MultiContext class
+       <http://svn.enthought.com/svn/enthought/CodeTools/trunk/enthought/contexts/multi_context.py>`_
+       in the Enthought `CodeTools package
+       <https://github.com/enthought/codetools>`_\ has options to support
+       writing to any mapping in the chain.
+
+     * Django's `Context class
+       <http://code.djangoproject.com/browser/django/trunk/django/template/context.py>`_
+       for templating is a read-only chain of mappings.  It also features
+       pushing and popping of contexts similar to the
+       :meth:`~collections.ChainMap.new_child` method and the
+       :meth:`~collections.ChainMap.parents` property.
+
+     * The `Nested Contexts recipe
+       <http://code.activestate.com/recipes/577434/>`_ has options to control
+       whether writes and other mutations apply only to the first mapping or to
+       any mapping in the chain.
+
+     * A `greatly simplified read-only version of Chainmap
+       <http://code.activestate.com/recipes/305268/>`_\.
+
 :class:`Counter` objects
 ------------------------
 

Modified: python/branches/py3k/Lib/collections/__init__.py
==============================================================================
--- python/branches/py3k/Lib/collections/__init__.py	(original)
+++ python/branches/py3k/Lib/collections/__init__.py	Sat Feb 26 02:02:51 2011
@@ -636,7 +636,7 @@
 ###  ChainMap (helper for configparser and string.Template)
 ########################################################################
 
-class _ChainMap(MutableMapping):
+class ChainMap(MutableMapping):
     ''' A ChainMap groups multiple dicts (or other mappings) together
     to create a single, updateable view.
 

Modified: python/branches/py3k/Lib/configparser.py
==============================================================================
--- python/branches/py3k/Lib/configparser.py	(original)
+++ python/branches/py3k/Lib/configparser.py	Sat Feb 26 02:02:51 2011
@@ -120,7 +120,7 @@
 """
 
 from collections.abc import MutableMapping
-from collections import OrderedDict as _default_dict, _ChainMap
+from collections import OrderedDict as _default_dict, ChainMap as _ChainMap
 import functools
 import io
 import itertools

Modified: python/branches/py3k/Lib/string.py
==============================================================================
--- python/branches/py3k/Lib/string.py	(original)
+++ python/branches/py3k/Lib/string.py	Sat Feb 26 02:02:51 2011
@@ -46,7 +46,7 @@
 
 ####################################################################
 import re as _re
-from collections import _ChainMap
+from collections import ChainMap
 
 class _TemplateMetaclass(type):
     pattern = r"""
@@ -100,7 +100,7 @@
         if not args:
             mapping = kws
         elif kws:
-            mapping = _ChainMap(kws, args[0])
+            mapping = ChainMap(kws, args[0])
         else:
             mapping = args[0]
         # Helper function for .sub()
@@ -126,7 +126,7 @@
         if not args:
             mapping = kws
         elif kws:
-            mapping = _ChainMap(kws, args[0])
+            mapping = ChainMap(kws, args[0])
         else:
             mapping = args[0]
         # Helper function for .sub()

Modified: python/branches/py3k/Lib/test/test_collections.py
==============================================================================
--- python/branches/py3k/Lib/test/test_collections.py	(original)
+++ python/branches/py3k/Lib/test/test_collections.py	Sat Feb 26 02:02:51 2011
@@ -11,7 +11,7 @@
 import re
 import sys
 from collections import UserDict
-from collections import _ChainMap as ChainMap
+from collections import ChainMap
 from collections.abc import Hashable, Iterable, Iterator
 from collections.abc import Sized, Container, Callable
 from collections.abc import Set, MutableSet
@@ -21,7 +21,7 @@
 
 
 ################################################################################
-### _ChainMap (helper class for configparser and the string module)
+### ChainMap (helper class for configparser and the string module)
 ################################################################################
 
 class TestChainMap(unittest.TestCase):

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Sat Feb 26 02:02:51 2011
@@ -35,6 +35,8 @@
 Library
 -------
 
+- Issue #11297: Add collections.ChainMap().
+
 - Issue #10755: Add the posix.fdlistdir() function.  Patch by Ross Lagerwall.
 
 - Issue #4761: Add the *at() family of functions (openat(), etc.) to the posix


More information about the Python-checkins mailing list