ChainMap as a context manager
![](https://secure.gravatar.com/avatar/482f6832b98eccb86e2a5dc4de8aad91.jpg?s=120&d=mm&r=g)
How about adding the context manager protocol to collections.ChainMap, as an in-place combination of new_child() and parents()? The effect would simulate lexical scope using the with-statement. Trivial to do customly but always nice when builtin or stdlib types support the context manager protocol. :)
![](https://secure.gravatar.com/avatar/3ab03c2cab54cc59d04b4b1cba58ab57.jpg?s=120&d=mm&r=g)
On Sun, Aug 7, 2011 at 10:50 AM, dag.odenhall@gmail.com <dag.odenhall@gmail.com> wrote:
How about adding the context manager protocol to collections.ChainMap, as an in-place combination of new_child() and parents()? The effect would simulate lexical scope using the with-statement.
Trivial to do customly but always nice when builtin or stdlib types support the context manager protocol. :)
I don't understand the utility of such a thing. Can you post a use case or two to make it clearer to people like me? Mike
![](https://secure.gravatar.com/avatar/482f6832b98eccb86e2a5dc4de8aad91.jpg?s=120&d=mm&r=g)
On 7 August 2011 17:02, Mike Graham <mikegraham@gmail.com> wrote:
On Sun, Aug 7, 2011 at 10:50 AM, dag.odenhall@gmail.com <dag.odenhall@gmail.com> wrote:
How about adding the context manager protocol to collections.ChainMap, as an in-place combination of new_child() and parents()? The effect would simulate lexical scope using the with-statement.
Trivial to do customly but always nice when builtin or stdlib types support the context manager protocol. :)
I don't understand the utility of such a thing. Can you post a use case or two to make it clearer to people like me?
To be quite honest I'm not perfectly sure myself; it just seemed like such a natural context manager that I got curious if it was just overlooked or if I was missing something. If it turns out it would make sense it might be good to realize it early before the 3.3 release?
![](https://secure.gravatar.com/avatar/f3ba3ecffd20251d73749afbfa636786.jpg?s=120&d=mm&r=g)
On Mon, Aug 8, 2011 at 1:43 PM, dag.odenhall@gmail.com <dag.odenhall@gmail.com> wrote:
To be quite honest I'm not perfectly sure myself; it just seemed like such a natural context manager that I got curious if it was just overlooked or if I was missing something. If it turns out it would make sense it might be good to realize it early before the 3.3 release?
While the enthusiasm is appreciated, it's useful to run through a quick sanity check before lobbing an email into the inboxes of all of the python-ideas subscribers: 1. Do I have a concrete use case in mind? 2. If yes, is that use case highly specific to my current problem domain, or is it more broadly applicable than that? 3. If no, is there a clear inconsistency or wart that presents a roadblock to learning the language that the idea would address? We're actually fairly conservative about what we add to the core language and the standard library, so we greatly prefer ideas that have been "battle tested" outside the standard library first. Py3k did include a couple of experiments that are still in the process of proving themselves (i.e. function annotations and new-style string formatting), but such changes are definitely the exception rather than the rule. In this case, it is trivial for someone to write a collections.ChainMap based decorator that works as you describe: @contextmanager def scope(chain=None): if scope is None: yield ChainMap({}) else: yield chain.new_child() with scope() as outer: with scope(outer) as inner1: # Manipulate inner1 without affecting outer However, that adds no real expressivity and is unlikely to be particularly useful in practice, since most lexical scoping problems can be handled using *actual* lexical scoping. ChainMap is useful for cases like multiple levels of configuration data where the scoping occurs at runtime rather than in the source code. Hiding a call new_child() inside a context manager just to get an additional level of indentation is fairly pointless. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
![](https://secure.gravatar.com/avatar/f3ba3ecffd20251d73749afbfa636786.jpg?s=120&d=mm&r=g)
On Mon, Aug 8, 2011 at 2:11 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
@contextmanager def scope(chain=None): if scope is None: yield ChainMap({}) else: yield chain.new_child()
s/scope/chain/ on the first line of the function body. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
![](https://secure.gravatar.com/avatar/482f6832b98eccb86e2a5dc4de8aad91.jpg?s=120&d=mm&r=g)
On 8 August 2011 06:11, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Mon, Aug 8, 2011 at 1:43 PM, dag.odenhall@gmail.com <dag.odenhall@gmail.com> wrote:
To be quite honest I'm not perfectly sure myself; it just seemed like such a natural context manager that I got curious if it was just overlooked or if I was missing something. If it turns out it would make sense it might be good to realize it early before the 3.3 release?
While the enthusiasm is appreciated, it's useful to run through a quick sanity check before lobbing an email into the inboxes of all of the python-ideas subscribers:
1. Do I have a concrete use case in mind? 2. If yes, is that use case highly specific to my current problem domain, or is it more broadly applicable than that? 3. If no, is there a clear inconsistency or wart that presents a roadblock to learning the language that the idea would address?
We're actually fairly conservative about what we add to the core language and the standard library, so we greatly prefer ideas that have been "battle tested" outside the standard library first. Py3k did include a couple of experiments that are still in the process of proving themselves (i.e. function annotations and new-style string formatting), but such changes are definitely the exception rather than the rule.
In this case, it is trivial for someone to write a collections.ChainMap based decorator that works as you describe:
@contextmanager def scope(chain=None): if scope is None: yield ChainMap({}) else: yield chain.new_child()
with scope() as outer: with scope(outer) as inner1: # Manipulate inner1 without affecting outer
However, that adds no real expressivity and is unlikely to be particularly useful in practice, since most lexical scoping problems can be handled using *actual* lexical scoping. ChainMap is useful for cases like multiple levels of configuration data where the scoping occurs at runtime rather than in the source code. Hiding a call new_child() inside a context manager just to get an additional level of indentation is fairly pointless.
I meant it in-place, so the scope of the context is more than mere indentation: scope = ChainMap() scope['foo'] = 1 with scope: scope['foo'] = 2 with scope: scope['foo'] = 3 assert scope['foo'] == 2 assert scope['foo'] == 1
participants (3)
-
dag.odenhall@gmail.com
-
Mike Graham
-
Nick Coghlan