[Python-ideas] Dictionary destructing and unpacking.

Oleg Broytman phd at phdru.name
Thu Jun 8 01:51:39 EDT 2017


Thank you! This overview really helps!

On Thu, Jun 08, 2017 at 11:18:06AM +1000, Steven D'Aprano <steve at pearwood.info> wrote:
> On Wed, Jun 07, 2017 at 06:14:08PM +0000, Nick Humrich wrote:
> 
> > It would be cool to have a syntax that would unpack the dictionary to
> > values based on the names of the variables. Something perhaps like:
> > 
> > a, b, c = **mydict
> 
> This was discussed (briefly, to very little interest) in March/April 
> 2008:
> 
> https://mail.python.org/pipermail/python-ideas/2008-March/001511.html
> https://mail.python.org/pipermail/python-ideas/2008-April/001513.html
> 
> and then again in 2016, when it spawned a very large thread starting 
> here:
> 
> https://mail.python.org/pipermail/python-ideas/2016-May/040430.html
> 
> I know there's a lot of messages, but I STRONGLY encourage anyone, 
> whether you are for or against this idea, to read the previous 
> discussion before continuing it here.
> 
> Guido was luke-warm about the **mapping syntax:
> 
> https://mail.python.org/pipermail/python-ideas/2016-May/040466.html
> 
> Nathan Schneider proposed making dict.values() take optional key names:
> 
> https://mail.python.org/pipermail/python-ideas/2016-May/040517.html
> 
> Guido suggested that this should be a different method:
> 
> https://mail.python.org/pipermail/python-ideas/2016-May/040518.html
> 
> My recollection is that the discussion evertually petered out with a 
> more-or-less consensus that having a dict method (perhaps "getvalues"?) 
> plus regular item unpacking is sufficient for the common use-case of 
> unpacking a subset of keys:
> 
> prefs = {'width': 80, 'height': 200, 'verbose': False, 'mode': PLAIN,
>          'name': 'Fnord', 'flags': spam|eggs|cheese, ... }  
>          # dict includes many more items
> 
> width, height, size = prefs.getvalues(
>         'width', 'height', 'papersize',
>         )
> 
> 
> This trivially supports the cases where keys are not strings or valid 
> identifiers:
> 
> class_, spam, eggs = mapping.getvalues('class', 42, '~')
> 
> It easily supports assignment targets which aren't simple variable 
> names:
> 
> obj.attribute[index], spam().attr = mapping.getvalues('foo', 'bar')
> 
> An optional (defaults to False) "pop" keyword argument supports 
> extracting and removing values from the dict in one call, which is 
> commonly needed inside __init__ methods with **kwargs:
> 
> class K(parent):
>     def __init__(self, a, b, c, **kwargs):
>         self.spam = kwargs.pop('spam')
>         self.eggs = kwargs.pop('eggs')
>         self.cheese = kwargs.pop('cheese')
>         super().__init__(a, b, c, **kwargs)
>         
> 
> becomes:
> 
>         self.spam, self.eggs, self.cheese = kwargs.getvalues(
>                 'spam eggs cheese'.split(), pop=True
>                 )
> 
> 
> I don't recall this being proposed at the time, but we could support 
> keyword arguments for missing or default values:
> 
> DEFAULTS = {'height': 100, 'width': 50}
> prefs = get_prefs()  # returns a dict
> 
> height, width, size = prefs.getvalues(
>         'height', 'width', 'papersize',
>         defaults=DEFAULTS,
>         missing=None
>         )
> 
> 
> A basic implementation might be:
> 
> # Untested.
> def getvalues(self, *keys, pop=False, defaults=None, missing=SENTINEL):
>     values = []
>     for key in keys:
>         try:
>             x = self[key]
>         except KeyError:
>             if defaults is not None:
>                 x = defaults.get(key, SENTINEL)
>             if x is SENTINEL:
>                 x = missing
>             if x is SENTINEL:
>                 raise KeyError('missing key %r' % key)
>         if pop:
>             del self[key]
>         values.append(x)
>     return tuple(values)
> 
> 
> 
> It's a bit repetitive for the common case where keys are the same as the 
> assignment targets, but that's a hard problem to solve, and besides, 
> "explicit is better than implicit".
> 
> It also doesn't really work well for the case where you want to blindly create new assignment targets for 
> *every* key, but:
> 
> - my recollection is that nobody really came up with a convincing 
>   use-case for this (apologies if I missed any);
> 
> - and if you really need this, you can do:
> 
>     locals().update(mapping)
> 
> inside a class body or at the top-level of the module (but not inside a 
> function).
> 
> Please, let's save a lot of discussion here and now, and just read the 
> 2016 thread: it is extremely comprehensive.
> 
> 
> -- 
> Steve

Oleg.
-- 
     Oleg Broytman            http://phdru.name/            phd at phdru.name
           Programmers don't die, they just GOSUB without RETURN.


More information about the Python-ideas mailing list