[Python-ideas] Unpacking a dict

Ethan Furman ethan at stoneleaf.us
Wed May 25 19:41:57 EDT 2016


On 05/25/2016 03:52 PM, Michael Selik wrote:

> I really like Sven's example.
>
> py> mapping = {"a": 1, "b": 2, "c": 3}
>      py>{"a": x, "b": y, "c": 2} = mapping
>      Traceback:
>      ValueError: key 'c' does not match value 2
>
> Even if we don't implement this feature in the first version of dict
> unpacking, we should keep the option open.

Ugh, no.  That is not dict unpacking, it's dict matching and unpacking, 
which is way beyond the simplicity of just unpacking.

> On Wed, May 25, 2016 at 4:14 PM Ethan Furman wrote:
>>
>> The proposal is this:
>>     a, b = **mapping
>>
>> The advantages:
>> - much more readable
>> - less duplication
>
>
> Why doesn't that work for tuple unpacking?
>      py> a, b = *iterable
>      SyntaxError
>
> Whatever the reasons, that syntax wasn't chosen for tuple unpacking.
> Dict unpacking should mimic tuple unpacking. If I saw ``a, b =

Good point.  So it should just be:

   a, b = mapping

or
   a, b, **_ = mapping  # when you don't care about the rest


> Unpacking a tuple mirrors a tuple display.
>
>      py> (a, b) = (1, 2)
>      py> (a, b) = (1, 2, 3)
>      ValueError: too many values to unpack, expected 2

I think that most Pythonistas would say:

   a, b = 1, 2  # look ma!  no round brackets!

> Unpacking a dict should mirror a dict display.
>
>      py> {'x': a, 'y': b} = {'x': 1, 'y': 2}

Absolutely not, at least not for the simple case.  A simple tuple/list 
unpack looks like

   a, b, c = an_iterable

while a more complicated one looks like

   a, b, c = an_iterable[7], an_iterable[3], an_iterable[10]

So a simple dict unpack should look like

   some_dict = dict(a=99, b=44, c=37)
   a, b, c = some_dict

and if we don't need all the items

   a, b, **_ = some_dict

and if we want to rename the keys on extraction

   x, y, z = some_dict['a'], some_dict['b'], some_dict['c']

or, as Random pointed out

   x, y, z = [some_dict[k] for k in ('a', 'b', 'c')]

which has a nice symmetry to it.


> py> {'x': a, 'y': b} = {'x': 1, 'y': 2, 'z': 3}
>      ValueError: too many keys to unpack, expected {'x', 'y'}
>
> As Brendan and others have mentioned, the more concise syntax you're
> proposing will not support non-string keys and cannot be enhanced to
> support Erlang/Clojure/etc-style matching on values.

And as I have mentioned, matching syntax is out-of-scope for an 
unpacking proposal.  At most, it should be a "let's not paint ourselves 
into a corner" type of concern -- and I must admit I don't see why

   a, b, c = some_dict

rules out

  {'x': a, 'y':b} = some_dict

as a pattern-matching construct.


> On Wed, May 25, 2016 at 11:18 AM Paul Moore wrote:
>>
>> get a set of elements and *ignore* the rest:
>
> If it's just one or two, that's easy. Use an underscore to indicate you
> don't care. Again, I'm trying to mirror a dict display. This is the same
> way that tuple unpacking solves the problem.
>
>      py> (a, b, _) = (1, 2, 3)
>      py> {'x': a, 'y': b, 'z': _} = {'x': 1, 'y': 2, 'z': 3}

Since you've repeated yourself, I will too.  ;)

The parenthesis are legal, but usually unnecessary noise, when 
creating/unpacking a tuple.

--
~Ethan~


More information about the Python-ideas mailing list