[Python-ideas] Allow using ** twice
Nick Coghlan
ncoghlan at gmail.com
Fri Jun 7 04:27:49 CEST 2013
On 7 June 2013 08:38, Nick Coghlan <ncoghlan at gmail.com> wrote:
>
> > If you wanted to do that you'd use a Counter:
> >
> > >>> from collections import Counter
> > >>> dict1 = Counter()
> > >>> dict2 = Counter()
> >
> > >>> dict1["arg1"] = 5
> > >>> dict2["arg1"] = 3
> > >>> dict1 + dict2
> > Counter({'arg1': 8})
> >
> > As for dicts, -1.
>
> *If* anything were to change for dicts, it would be to change or add methods (such as a new alternative constructor) rather than add operator support.
In an attempt to frame the discussion more productively:
1. Python already has a well-defined notion of what it means to merge
two dictionaries: d1.update(d2)
2. This notion is asymmetric, thus it makes sense to use an asymmetric
notation for it (specifically, a method call) rather than a
traditionally symmetric binary operator notation like + or |.
3. However, like other mutating methods on builtin types, dict.update
does *not* return a reference to the original object (this is
deliberate, to encourage the treatment of containers as immutable when
using a functional programming style)
4. Thus, just as sorted() was added as a functional counterpart to
list.sort, is there something that can be added as a functional
counterpart to dict.update?
There are a few available responses to this kind of question:
1. Do nothing and preserve the status quo
2. Add a new standard library function.
3. Add a new non-mutating instance method.
4. Change the instance constructor (or add an alternate constructor).
5. Add a new builtin
6. Add new syntax
Merging dictionaries isn't a common enough use case for options 5 or 6
to be on the table.
The signature of the dict constructor (and that of dict.update) is
already incredibly complicated, so you really wouldn't want to add
support for multiple positional arguments to those. Coming up with a
good name for an alternate constructor is also difficult, effectively
ruling out option 4 as well.
The following variants (based on Haoyi's list of existing
alternatives) pretty much cover option 1:
z = dict(x.items() + y.items())
z = dict(ChainMap(y, x)) # Note the reversed order of the arguments!
z = copy_and_update(x, y)
Where ChainMap is collections.ChainMap and copy_and_update is something like:
def copy_and_update(base, *others):
result = base.copy()
for other in others:
result.update(other)
return result
That last alternative also suggests possible names for a standard
library function (collections.copy_and_update) or a new instance
method (dict.copy_and_update and collections.Mapping.copy_and_update).
The need to reverse the arguments to ChainMap to get the standard
update behaviour, together with the fact an instance method would need
to be implemented in at least two places, means that I am +0 on the
idea of adding a helper function to collections (in the spirit of
providing one-obvious-way to do it), -0 for adding an instance method
or retaining the status quo indefinitely, but -1 for the other
alternatives.
Cheers,
Nick.
>
> Cheers,
> Nick.
>
> >
> >
> > _______________________________________________
> > Python-ideas mailing list
> > Python-ideas at python.org
> > http://mail.python.org/mailman/listinfo/python-ideas
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
More information about the Python-ideas
mailing list