
A practical usage of ChainMap in Python - florimondmanca
https://blog.florimondmanca.com/a-practical-usage-of-chainmap-in-python
======
dangom
I see the example use case is exactly the same as the one given in the python
documentation [1]. Any other practical use cases?

[1]
[https://docs.python.org/3.7/library/collections.html#collect...](https://docs.python.org/3.7/library/collections.html#collections.ChainMap)

~~~
thedirt0115
It's nice for anything with nested scopes -- Example that came to mind since a
link to Crafting Interpreters was also on the front page: Variable lookup for
for an interpreter. If each scope gets its own set of bindings, you can make a
ChainMap from most specific to least specific and look up values from that
instead of manually traversing scopes.

------
Sean1708

      >>> from collections import ChainMap
      >>> inv = ChainMap({'Monopoly': 20, 'Nintendo': 200}, {'iMac': 1000, 'Chromebook': 800, 'PC': 400}, {'Jeans': 40, 'T-Shirt': 10})
      >>> inv['iMac'] = 9001
      >>> inv
      ChainMap({'Monopoly': 20, 'Nintendo': 200, 'iMac': 9001}, {'iMac': 1000, 'PC': 400, 'Chromebook': 800}, {'T-Shirt': 10, 'Jeans': 40})
    

This strikes me very much as the wrong default behaviour. If you want the (IMO
expected) behaviour of updating maps later in the list, the docs advocate
creating a entirely new class with overridden set and delete methods[0].
That's not the end of the world, but if they had made this the default
behaviour then the getting the current behaviour would just be

    
    
      chain_map.maps[0][key] = value
    

and you wouldn't need to create a new class at all.

Does anyone know why this decision was made?

[0]:
[https://docs.python.org/3.7/library/collections.html#chainma...](https://docs.python.org/3.7/library/collections.html#chainmap-
examples-and-recipes)

~~~
pmart123
hmm. That is not what I would have expected. I would have thought it would
update the value of the first map with the key "iMac", otherwise, add the key
to the top level. The same would go for:

>>> del inv['IMac']

deleting the key in the first mapping it appears. My guess is it is designed
to ensure that updating a key will not update accidentally update a default
mapping? This behavior could easily be prevented though by:

>>> from types import MappingProxyType >>> DEFAULTS =
MappingProxyType(default_dict) >>> ChainMap(overrides, DEFAULTS)

~~~
andreareina
Seems to be a strict design goal that the nothing below the top-most mapping
is changed, which I appreciate.

------
mixmastamyk
There are a few modules on PyPI (env, ezenv) that make the environment lookup
portion more convenient/robust, by selecting a prefix for your application
config. (Or write it yourself.) A prefix function that returns a mapping with
the keys sliced and lowercased, works like this:

    
    
        >>> env.prefix('XDG_')
        {'config_dirs': '…', 'current_desktop': '…', 
         'session_type': 'x11', 'vtnr': '7', …}

------
grusel
I did not see much value over the standard documentation or the referenced
blog post in this blog post at hand.

