[Python-Dev] Analog of PEP 448 for dicts (unpacking in assignment with dict rhs)

Ben Usman bigobangux at gmail.com
Fri Nov 10 22:53:44 EST 2017


The following works now:

seq = [1, 2]
d = {'c': 3, 'a': 1, 'b': 2}

(el1, el2) = *seq
el1, el2 = *seq
head, *tail = *seq

seq_new = (*seq, *tail)
dict_new = {**d, **{'c': 4}}

def f(arg1, arg2, a, b, c):
pass

f(*seq, **d)

It seems like dict unpacking syntax would not be fully coherent with
list unpacking syntax without something like:

{b, a, **other} = **d

Because iterables have both syntax for function call unpacking and
"rhs in assignment unpacking" and dict has only function call
unpacking syntax.

I was not able to find any PEPs that suggest this (search keywords:
"PEP 445 dicts", "dictionary unpacking assignment", checked PEP-0),
however, let me know if I am wrong.

The main use-case, in my understating, is getting shortcuts to
elements of a dictionary if they are going to be used more then
ones later in the scope. A made-up example is using a config to
initiate a bunch of things with many config arguments with long
names that have overlap in keywords used in initialization.

One should either write long calls like

start_a(config['parameter1'], config['parameter2'],
config['parameter3'], config['parameter4'])

start_b(config['parameter3'], config['parameter2'],
config['parameter3'], config['parameter4'])

many times or use a list-comprehension solution mentioned above.

It becomes even worse (in terms of readability) with nested structures.

start_b(config['group2']['parameter3'], config['parameter2'],
config['parameter3'], config['group2']['parameter3'])


## Rationale

Right now this problem is often solved using [list] comprehensions,
but this is somewhat verbose:

a, b = (d[k] for k in ['a', 'b'])

or direct per-instance assignment (looks simple for with
single-character keys, but often becomes very verbose with
real-world long key names)

a = d['a']
b = d['b']

Alternatively one could have a very basic method\function
get_n() or __getitem__() accepting more then a single argument

a, b = d.get_n('a', 'b')
a, b = get_n(d, 'a', 'b')
a, b = d['a', 'b']

All these approaches require verbose double-mentioning of same
key. It becomes even worse if you have nested structures
of dictionaries.

## Concerns and questions:

0. This is the most troubling part,  imho, other questions
are more like common thoughts. It seems (to put it mildly)
weird that execution flow depends on names of local variables.

For example, one can not easily refactor these variable names. However,
same is true for dictionary keys anyway: you can not suddenly decide
and refactor your code to expect dictionaries with keys 'c' and
'd' whereas your entire system still expects you to use dictionaries
with keys 'a' and 'b'. A counter-objection is that this specific
scenario is usually handled with record\struct-like classes  with
fixed members rather then dicts, so this is not an issue.

Quite a few languages (closure and javascript to name a few) seem
to have this feature now and it seems like they did not suffer too
much from refactoring hell. This does not mean that their approach
is good, just that it is "manageable".

1. This line seems coherent with sequence syntax, but redundant:
{b, a, **other} = **d

and the following use of "throwaway" variable just looks poor visually
{b, a, **_} = **d

could it be less verbose like this
{b, a} = **d

but it is not very coherent with lists behavior.

E.g. what if that line did not raise something like "ValueError:
Too many keys to unpack, got an unexpected keyword argument 'c'".

2. Unpacking in other contexts

{self.a, b, **other} = **d

should it be interpreted as
self.a, b = d['a'], d['b']

or

self.a, b = d['self.a'], d['b']

probably the first, but what I am saying is that these name-extracting
rules should be strictly specified and it might not be trivial.

---
Ben
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20171110/a3ee6569/attachment.html>


More information about the Python-Dev mailing list