[Python-ideas] Unpacking a dict

Michael Selik michael.selik at gmail.com
Wed May 25 18:52:01 EDT 2016

I'm responding here to Sven, Random832, and Ethan.

On Wed, May 25, 2016 at 10:08 AM Sven R. Kunze <srkunze at mail.de> wrote:

> I for one find this one of the shortest proposals compared to other recent
> proposals I have seen.  :)

If it's easy to explain, it might be a good idea :-)

On Wed, May 25, 2016 at 10:40 AM Random832 <random832 at fastmail.com> wrote:

> On Wed, May 25, 2016, at 09:11, Michael Selik wrote:
> > Clojure also supports mapping destructuring. Let's add that to Python!
> >
> >     py> mapping = {"a": 1, "b": 2, "c": 3}
> >     py> {"a": x, "b": y, "c": z} = mapping
> How is this better than:
> py> mapping = {"a": 1, "b": 2, "c": 3}
> py> x, y, z = mapping[k] for k in ("a", "b", "c")

I think the thread has formed a consensus that there are at least 2 clear
use cases for unpacking. Not surprisingly, they're the same use cases for
both tuple unpacking and dict unpacking.
1. declarative schema validation while simultaneously binding variables
2. declaratively extracting a subset of the elements

In your example, what if the dict has more keys than you are looping over?
Look at the other part of my proposal:

    py> mapping = {"a": 1, "b": 2, "c": 3}
    py> {"a": x, "b": y} = mapping
    ValueError: too many keys to unpack

I really like Sven's example.

    py> mapping = {"a": 1, "b": 2, "c": 3}
    py> {"a": x, "b": y, "c": 2} = mapping
    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.

On Wed, May 25, 2016 at 4:14 PM Ethan Furman <ethan at stoneleaf.us> 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

Whatever the reasons, that syntax wasn't chosen for tuple unpacking. Dict
unpacking should mimic tuple unpacking. If I saw ``a, b = **mapping`` I
would expect ``a, b = *iterable``.

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

Unpacking a dict should mirror a dict display.

    py> {'x': a, 'y': b} = {'x': 1, 'y': 2}
    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.

On Wed, May 25, 2016 at 11:18 AM Paul Moore <p.f.moore at gmail.com> 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}

If you need to ignore many, we need to extend dict unpacking the same way
that tuple unpacking was extended in PEP 3132.

    py> (a, b, *rest) = (1, 2, 3, 4)
    py> a, b, rest
    (1, 2, (3, 4))
    py> {'x': a, 'y', b, **rest} = {'x': 1, 'y': 2, 'z': 3, 'w': 4}
    py> a, b, rest
    (1, 2, {'w': 4, 'z': 3})

Sure, **rest isn't valid in a dict display, but it's the same with tuple
unpacking: *rest isn't valid in a tuple display.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20160525/8965bbbe/attachment.html>

More information about the Python-ideas mailing list