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

Ben Usman bigobangux at gmail.com
Sat Nov 11 01:26:19 EST 2017


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
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20171111/960058ca/attachment-0001.html>


More information about the Python-Dev mailing list