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

Joao S. O. Bueno jsbueno at python.org.br
Sat Nov 11 19:09:58 EST 2017


Ben, I have a small package which enables one to do:

with MapGetter(my_dictionary):
    from my_dictionary import a, b, parameter3

If this interests you, contributions so it can get hardenned for
mainstram acceptance are welcome.
https://github.com/jsbueno/extradict

On 11 November 2017 at 04:26, Ben Usman <bigobangux at gmail.com> wrote:
> Got it, thank you. I'll go and check it out!
>
> On Nov 11, 2017 01:22, "Jelle Zijlstra" <jelle.zijlstra at gmail.com> wrote:
>>
>>
>>
>> 2017-11-10 19:53 GMT-08:00 Ben Usman <bigobangux at gmail.com>:
>>>
>>> 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.
>>>
>> It was discussed at great length on Python-ideas about a year ago. There
>> is a thread called "Unpacking a dict" from May 2016.
>>
>>>
>>> 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
>>>
>>> _______________________________________________
>>> Python-Dev mailing list
>>> Python-Dev at python.org
>>> https://mail.python.org/mailman/listinfo/python-dev
>>> Unsubscribe:
>>> https://mail.python.org/mailman/options/python-dev/jelle.zijlstra%40gmail.com
>>>
>>
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/jsbueno%40python.org.br
>


More information about the Python-Dev mailing list