@@ -23,6 +23,7 @@ Python's general purpose built-in containers, :class:`dict`, :class:`list`,
2323===================== ====================================================================
2424:func: `namedtuple ` factory function for creating tuple subclasses with named fields
2525:class: `deque ` list-like container with fast appends and pops on either end
26+ :class: `ChainMap ` dict-like class for creating a single view of multiple mappings
2627:class: `Counter ` dict subclass for counting hashable objects
2728:class: `OrderedDict ` dict subclass that remembers the order entries were added
2829:class: `defaultdict ` dict subclass that calls a factory function to supply missing values
@@ -37,6 +38,119 @@ Python's general purpose built-in containers, :class:`dict`, :class:`list`,
3738 as well.
3839
3940
41+ :class: `ChainMap ` objects
42+ -------------------------
43+
44+ A :class: `ChainMap ` class is provided for quickly linking a number of mappings
45+ so they can be treated as a single unit. It is often much faster than creating
46+ a new dictionary and running multiple :meth: `~dict.update ` calls.
47+
48+ The class can be used to simulate nested scopes and is useful in templating.
49+
50+ .. class :: ChainMap(*maps)
51+
52+ A :class: `ChainMap ` groups multiple dicts or other mappings together to
53+ create a single, updateable view. If no *maps * are specified, a single empty
54+ dictionary is provided so that a new chain always has at least one mapping.
55+
56+ The underlying mappings are stored in a list. That list is public and can
57+ accessed or updated using the *maps * attribute. There is no other state.
58+
59+ Lookups search the underlying mappings successively until a key is found. In
60+ contrast, writes, updates, and deletions only operate on the first mapping.
61+
62+ A class:`ChainMap ` incorporates the underlying mappings by reference. So, if
63+ one of the underlying mappings gets updated, those changes will be reflected
64+ in class:`ChainMap `.
65+
66+ All of the usual dictionary methods are supported. In addition, there is a
67+ *maps * attribute, a method for creating new subcontexts, and a property for
68+ accessing all but the first mapping:
69+
70+ .. attribute :: maps
71+
72+ A user updateable list of mappings. The list is ordered from
73+ first-searched to last-searched. It is the only stored state and can
74+ modified to change which mappings are searched. The list should
75+ always contain at least one mapping.
76+
77+ .. method :: new_child()
78+
79+ Returns a new :class: `ChainMap ` containing a new :class: `dict ` followed by
80+ all of the maps in the current instance. A call to ``d.new_child() `` is
81+ equivalent to: ``ChainMap({}, *d.maps) ``. This method is used for
82+ creating subcontexts that can be updated without altering values in any
83+ of the parent mappings.
84+
85+ .. attribute :: parents()
86+
87+ Returns a new :class: `ChainMap ` containing all of the maps in the current
88+ instance except the first one. This is useful for skipping the first map
89+ in the search. The use-cases are similar to those for the
90+ :keyword: `nonlocal ` keyword used in :term: `nested scopes <nested scope> `.
91+ The use-cases also parallel those for the builtin :func: `super ` function.
92+ A reference to ``d.parents `` is equivalent to: ``ChainMap(*d.maps[1:]) ``.
93+
94+ .. versionadded :: 3.3
95+
96+ Example of simulating Python's internal lookup chain::
97+
98+ import __builtin__
99+ pylookup = ChainMap(locals(), globals(), vars(__builtin__))
100+
101+ Example of letting user specified values take precedence over environment
102+ variables which in turn take precedence over default values::
103+
104+ import os, argparse
105+ defaults = {'color': 'red', 'user': guest}
106+ parser = argparse.ArgumentParser()
107+ parser.add_argument('-u', '--user')
108+ parser.add_argument('-c', '--color')
109+ user_specified = vars(parser.parse_args())
110+ combined = ChainMap(user_specified, os.environ, defaults)
111+
112+ Example patterns for using the :class: `ChainMap ` class to simulate nested
113+ contexts::
114+
115+ c = ChainMap() Create root context
116+ d = c.new_child() Create nested child context
117+ e = c.new_child() Child of c, independent from d
118+ e.maps[0] Current context dictionary -- like Python's locals()
119+ e.maps[-1] Root context -- like Python's globals()
120+ e.parents Enclosing context chain -- like Python's nonlocals
121+
122+ d['x'] Get first key in the chain of contexts
123+ d['x'] = 1 Set value in current context
124+ del['x'] Delete from current context
125+ list(d) All nested values
126+ k in d Check all nested values
127+ len(d) Number of nested values
128+ d.items() All nested items
129+ dict(d) Flatten into a regular dictionary
130+
131+ .. seealso ::
132+
133+ * The `MultiContext class
134+ <http://svn.enthought.com/svn/enthought/CodeTools/trunk/enthought/contexts/multi_context.py> `_
135+ in the Enthought `CodeTools package
136+ <https://github.com/enthought/codetools> `_\ has options to support
137+ writing to any mapping in the chain.
138+
139+ * Django's `Context class
140+ <http://code.djangoproject.com/browser/django/trunk/django/template/context.py> `_
141+ for templating is a read-only chain of mappings. It also features
142+ pushing and popping of contexts similar to the
143+ :meth: `~collections.ChainMap.new_child ` method and the
144+ :meth: `~collections.ChainMap.parents ` property.
145+
146+ * The `Nested Contexts recipe
147+ <http://code.activestate.com/recipes/577434/> `_ has options to control
148+ whether writes and other mutations apply only to the first mapping or to
149+ any mapping in the chain.
150+
151+ * A `greatly simplified read-only version of Chainmap
152+ <http://code.activestate.com/recipes/305268/> `_\.
153+
40154:class: `Counter ` objects
41155------------------------
42156
0 commit comments