What is the purpose of the collections. ChainMap?

In Python 3.3, the ChainMap class was added to the collections module:

The ChainMap class is provided for quick binding of several mappings; therefore, they can be considered as a single whole. This is often much faster than creating a new dictionary and making a few calls to update ().

Example:

 >>> from collections import ChainMap >>> x = {'a': 1, 'b': 2} >>> y = {'b': 10, 'c': 11} >>> z = ChainMap(y, x) >>> for k, v in z.items(): print(k, v) a 1 c 11 b 10 

It was motivated by this issue and published by it ( PEP was not created).

As far as I understand, this is an alternative to having an additional dictionary and maintaining it with update() .

Questions:

  • When is ChainMap used?
  • Are there any real world examples of ChainMap ?
  • Is it used in third-party libraries that switch to python3?

Bonus question: is there a way to use it in Python2.x?




I heard about this in the Transforming Code into Beautiful, Idiomatic Python Discussion by Raymond Hettinger, and I would like to add it to my toolkit, but I lack understanding when I should use it.

+48
python collections dictionary data-structures
Apr 30 '14 at 16:07
source share
4 answers

I like @ b4hand examples, and I really used in previous structures like ChainMap (but not ChainMap itself) for two purposes that he mentions: redefining multi-level configurations and emulating stack / region variables.

I would like to point out two other ChainMap motivations / advantages / differences compared to using the dict-update cycle, thus preserving only the โ€œfinalโ€ version:

  • Additional information: since the ChainMap structure is "multilevel", it supports the answer to the question: "Do I get a value of" default "or redefined? What is the initial value (default value)? At what level the value was redefined (borrowed @ b4hand config example: user-config or command-line-overrides)? Using a simple dict, the information needed to answer these questions is already lost.

  • Speed โ€‹โ€‹tradeoff: suppose you have N levels and no more than M keys in each, building a ChainMap takes O(N) and each search for O(N) worst case [*], and building a dict using the update loop takes O(NM) and each search is O(1) . This means that if you create frequently and execute only a few requests each time, or if M is large, the Lazy-construction ChainMap approach works in your favor.

[*] Analysis in (2) suggests that dict-access has the value O(1) , when in fact it is O(1) on average and O(M) worst case. More details here .

+44
May 03 '14 at 8:00
source share

I could use ChainMap for a configuration object where you have several configuration areas, such as command line options, user configuration file, and system configuration file. Since the queries are ordered in order in the constructor argument, you can override the settings in lower areas. I personally have not used or seen ChainMap , but this is not surprising, since this is a fairly recent addition to the standard library.

It can also be useful for emulating stack frames where you click and drag variable bindings if you yourself are trying to implement a lexical area.

The standard library documents for ChainMap provide several examples and links to similar implementations in third-party libraries. In particular, he calls the Djangos context class and the Enthought class MultiContext .

+26
May 2 '14 at 22:21
source share

I will hack this:

Chainmap looks like a bit of an abstraction. This is a good solution for a very specialized problem. I suggest this use case.

If you have:

  • multiple mappings (e.g. dicts)
  • some duplication of keys in these mappings (the same key can be displayed in several mappings, but not if all keys are displayed in all mappings)
  • A consuming application that wants to access the key value in relation to the highest priority, where there is full ordering for all the mappings for any given key (that is, mappings can have equal priority, but only if it is known that there is no duplication of the key in these mappings) (In a Python application, packages can live in the same directory (same priority), but must have different names, so by definition, the names of characters in this directory cannot be duplicate.)
  • the consuming application does not need to change the key value
  • while mappings must retain their independent identification and can be changed asynchronously by external force.
  • and the comparisons are large enough, expensive enough to access, or change often enough between application calls, that the cost of calculating the forecast (3) every time your application needs it is a significant problem for your application ...

Then, you might consider using a chain to create a view over a collection of mappings.

But this is an after-fact excuse. The Python guys ran into a problem, came up with a good solution in the context of their code, then did some extra work to distract their solution so that we could use it if we wanted. More power to them. But whether it depends on your problem to solve your problem.

+5
2 '14 at 19:43
source share

In order not to answer your question:

Bonus question: is there a way to use it in Python2.x?

 from ConfigParser import _Chainmap as ChainMap 

However, keep in mind that this is not a real ChainMap , it inherits from DictMixin and only defines:

 __init__(self, *maps) __getitem__(self, key) keys(self) # And from DictMixin: __iter__(self) has_key(self, key) __contains__(self, key) iteritems(self) iterkeys(self) itervalues(self) values(self) items(self) clear(self) setdefault(self, key, default=None) pop(self, key, *args) popitem(self) update(self, other=None, **kwargs) get(self, key, default=None) __repr__(self) __cmp__(self, other) __len__(self) 

Its implementation also does not seem particularly effective.

+4
Dec 17 '16 at 13:44
source share



All Articles