Re: [Python-ideas] Have dict().update() return its own reference.

Thanks, that's fair, for consistency. One use case for my question was a stackoverflow question regarding merging two dict's. If update() returned its own reference, and if we explicitly wanted a copy (instead of an in-place modification), we could have used dict(x).update(y) given x and y are both dict() instances. Cheers, Xav On 20 April 2012 22:35, Laurens Van Houtven <_@lvh.cc> wrote:

Masklinn schrieb am Fri, 20. Apr 2012, um 14:47:34 +0200:
If you start from dict instances, you could always use:
merged = dict(x, **y)
No, not always. Only if all keys of `y` are strings (and probably they should also be valid Python identifiers.) Cheers, Sven

On 2012-04-20, at 16:28 , Stefan Behnel wrote:
Not sure why, as with `dict.update` `dict` is defined as setting from the first argument, then setting from the keyword arguments (overriding keys originally set if any). Now of course that might not be obvious to people who don't know how dict works, but I fail to see why an other function which they don't know either will be any more "immediately clear". You may counter that a function taking (and merging) a sequence of mappings would "obviously" apply a left fold in merging the mappings, but in that case the dict constructor would "obviously" copy the positional then apply the keywords (which are after the positional). Which is exactly what happens.

On Fri, Apr 20, 2012 at 10:49 AM, Stefan Behnel <stefan_ml@behnel.de> wrote:
I seem to recall that CPython had a similar limitation in the past, but it was removed at some point. I will try to dig out the relevant discussion, but I think the consensus was that ** should not attempt validate the keys.

On 2012-04-20, at 20:30 , Victor Varvariuc wrote:
If they're huge mappings, you probably don't want to go around copying them either way[0] and would instead use more custom mappings, either some sort of joining proxy or something out of Okasaki (a clojure-style tree-based map with structural sharing for instance) [0] I'm pretty sure "being fast to copy when bloody huge" is not at the forefront of Python's dict priorities.

On 2012-04-20, at 23:41 , Paul Moore wrote:
Yeah, it's an example of the "joining proxy" thing. Though I'm not sure I like it being editable, or the lookup order when providing a sequence of maps (I haven't tested it but it appears the maps sequence is traversed front-to-back, I'd have found the other way around more "obvious", as if each sub-mapping was applied to a base through an update call). An other potential weirdness of this solution — I don't know how ChainMap behaves there, the documentation is unclear — is iteration over the map and mapping.items() versus [(key, mapping[key]) for key in mapping] potentially having very different behaviors/values since the former is going to return all key:value pairs but the latter is only going to return the key:(first value for key) pairs which may lead to significant repetitions any time a key is present in multiple contexts.

Masklinn wrote:
ChainMap is meant to emulate scoped lookups, e.g. builtins + globals + nonlocals + locals. Hence, newer scopes mask older scopes. "Locals" should be fast, hence it is at the front. As for being editable, I'm not sure what you mean here, but surely you don't object to it being mutable?
No, iteration over the ChainMap returns unique keys, not duplicates.
-- Steven

On 2012-04-21, at 02:24 , Steven D'Aprano wrote:
yes, my notes were in the context of the thread considering chainmap as a proxy for multiple mappings, I understand this was not the primary use case for chainmap
, e.g. builtins + globals + nonlocals + locals. Hence, newer scopes mask older scopes. "Locals" should be fast, hence it is at the front.
That's just a question of traversal order for the maps sequence, if the sequence is in the order you specify there: [builtins, globals, nonlocals, locals] then it can be traversed from the back for locals to have the highest priority. The difference in speed should be almost nil
As for being editable, I'm not sure what you mean here, but surely you don't object to it being mutable?
I do, though again that's considering the usage of chainmap as a proxy, not as a scope chain.
Ah, that's good. Would probably warrant mention in the documentation though.

Masklinn schrieb am Fri, 20. Apr 2012, um 14:47:34 +0200:
If you start from dict instances, you could always use:
merged = dict(x, **y)
No, not always. Only if all keys of `y` are strings (and probably they should also be valid Python identifiers.) Cheers, Sven

On 2012-04-20, at 16:28 , Stefan Behnel wrote:
Not sure why, as with `dict.update` `dict` is defined as setting from the first argument, then setting from the keyword arguments (overriding keys originally set if any). Now of course that might not be obvious to people who don't know how dict works, but I fail to see why an other function which they don't know either will be any more "immediately clear". You may counter that a function taking (and merging) a sequence of mappings would "obviously" apply a left fold in merging the mappings, but in that case the dict constructor would "obviously" copy the positional then apply the keywords (which are after the positional). Which is exactly what happens.

On Fri, Apr 20, 2012 at 10:49 AM, Stefan Behnel <stefan_ml@behnel.de> wrote:
I seem to recall that CPython had a similar limitation in the past, but it was removed at some point. I will try to dig out the relevant discussion, but I think the consensus was that ** should not attempt validate the keys.

On 2012-04-20, at 20:30 , Victor Varvariuc wrote:
If they're huge mappings, you probably don't want to go around copying them either way[0] and would instead use more custom mappings, either some sort of joining proxy or something out of Okasaki (a clojure-style tree-based map with structural sharing for instance) [0] I'm pretty sure "being fast to copy when bloody huge" is not at the forefront of Python's dict priorities.

On 2012-04-20, at 23:41 , Paul Moore wrote:
Yeah, it's an example of the "joining proxy" thing. Though I'm not sure I like it being editable, or the lookup order when providing a sequence of maps (I haven't tested it but it appears the maps sequence is traversed front-to-back, I'd have found the other way around more "obvious", as if each sub-mapping was applied to a base through an update call). An other potential weirdness of this solution — I don't know how ChainMap behaves there, the documentation is unclear — is iteration over the map and mapping.items() versus [(key, mapping[key]) for key in mapping] potentially having very different behaviors/values since the former is going to return all key:value pairs but the latter is only going to return the key:(first value for key) pairs which may lead to significant repetitions any time a key is present in multiple contexts.

Masklinn wrote:
ChainMap is meant to emulate scoped lookups, e.g. builtins + globals + nonlocals + locals. Hence, newer scopes mask older scopes. "Locals" should be fast, hence it is at the front. As for being editable, I'm not sure what you mean here, but surely you don't object to it being mutable?
No, iteration over the ChainMap returns unique keys, not duplicates.
-- Steven

On 2012-04-21, at 02:24 , Steven D'Aprano wrote:
yes, my notes were in the context of the thread considering chainmap as a proxy for multiple mappings, I understand this was not the primary use case for chainmap
, e.g. builtins + globals + nonlocals + locals. Hence, newer scopes mask older scopes. "Locals" should be fast, hence it is at the front.
That's just a question of traversal order for the maps sequence, if the sequence is in the order you specify there: [builtins, globals, nonlocals, locals] then it can be traversed from the back for locals to have the highest priority. The difference in speed should be almost nil
As for being editable, I'm not sure what you mean here, but surely you don't object to it being mutable?
I do, though again that's considering the usage of chainmap as a proxy, not as a scope chain.
Ah, that's good. Would probably warrant mention in the documentation though.
participants (10)
-
Alexander Belopolsky
-
Guido van Rossum
-
Laurens Van Houtven
-
Masklinn
-
Paul Moore
-
Stefan Behnel
-
Steven D'Aprano
-
Sven Marnach
-
Victor Varvariuc
-
Xavier Ho