<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Wed, May 25, 2016 at 9:56 PM Steven D'Aprano <<a href="mailto:steve@pearwood.info">steve@pearwood.info</a>> wrote:</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> This will be approximately as helpful as iterable unpacking<br>
<br>
What is your evidence for this claim?</blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">[For extracting from a large dictionary] I'd rather unpack manually:<br> classify, spacer, width = (prefs[k] for k in ('classify', 'spacer', 'width'))<br></blockquote><div><br></div><div>I agree that comprehensions plus tuple unpacking handle many possible use cases for dict unpacking.</div><div><br></div><div>There are many marginally-better situations that would just drum up endless back-and-forth about aesthetics. So let's look for a situation where dict unpacking handles well what current syntax struggles with.</div><div><br></div><div>An example of schema validation plus binding in the current syntax:</div><div>```</div><div> py> mapping = {'a': 1, 'b': 2}</div><div> py> schema = ('a', 'b')</div><div> py> unexpected = mapping.keys() - set(schema)</div><div> py> if unexpected:</div><div> ... raise ValueError('unexpected keys %r' % unexpected)</div><div> ...</div><div> py> x, y = (mapping[key] for key in schema)</div><div>```</div><div><br></div><div>With sets and comprehensions, that's very nice. More pleasant than most if not all other mainstream languages. Yet dict unpacking can be just a bit better --<span style="line-height:1.5"> more declarative, more say-what-you-mean, less thinking about algorithms. Fewer steps, too, but that's not very important.</span></div><div><br></div><div>The proposed syntax, examples of missing and excess keys.</div><div>```</div><div> py> mapping = {'a': 1, 'b': 2, 'c': 3}</div><div> py> {'a': x, 'b': y, 'c': z, 'd': s, 'e': t} = mapping</div><div> ValueError: missing 2 required keys 'd' and 'e'</div><div><div> py> {'a': x, 'b': y} = mapping</div><div> ValueError: got an unexpected key 'c'</div></div><div>```</div><div><br></div><div>If you tell me that's not enough better to justify changing the language, I won't argue very much. I agree that example, if that's the only use case, would need to be backed up by extensive review of code of major projects to see how much improvement it'd really provide.</div><div><br></div><div>Unpacking really starts to shine when doing nested/recursive destructuring.</div><div><br></div><div>My proposed syntax:</div><div><div>```</div><div> py> d = {'a': 1,</div><div> ... 'b': {'c': 2, 'd': 3}}</div><div> py> {'a': x, 'b': {'c': y, 'd': y}} = d</div><div> py> x, y, z</div><div> 1, 2, 3</div><div>```</div></div><div><br></div><div>In current syntax, e<span style="line-height:1.5">ven simply specifying the schema is troublesome </span><span style="line-height:1.5">if the order of keys is to be preserved for binding </span><span style="line-height:1.5">to the desired names.</span></div><div><div><br></div><div>```</div><div> >>> mapping = {'a': 1, 'b': {'c': 2, 'd': 3}}</div><div> >>> schema = OrderedDict([('a', None),</div><div> ... ('b', OrderedDict([('c', None), ('d', None)]))])</div><div> >>> x, y, z = ...</div><div>```</div></div><div><br></div><div>I tried writing out a couple comprehensions for the binding, but they were *ugly*. The traversal of nested mapping <span style="line-height:1.5">for validation, flattening and assignment needs</span><span style="line-height:1.5"> a recursive function call or you'll end up with a disaster of nested loops.</span></div><div><br></div><div><span style="line-height:1.5">And lastly, if you have your eye on the prize (pattern matching) then establishing a full-featured dict unpacking is a big step in the right direction. I may not have stated it when I started this thread, but the initial motivation for dict unpacking was the trouble we were having in our discussion of pattern matching. I wanted to break that big problem apart into smaller problems.</span></div><div><span style="line-height:1.5"><br></span></div><div><span style="line-height:1.5">A possible (not proposed) syntax for dict and tuple pattern matching:</span></div><div><span style="line-height:1.5">```</span></div><div> py> {'a': x, 'b': 0} = {'a': 1, 'b': 2}</div><div> ValueError: key 'b' does not match value 0</div><div><div> py> (a, 0) = (1, 2)</div><div> ValueError: index 1 does not match value 0</div></div><div><span style="line-height:1.5">```</span></div><div><span style="line-height:1.5"><br></span></div><div><span style="line-height:1.5"><br></span></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">def spam(self, a, b, **kwargs):<br>
...<br>
<br>
I'd like to unpack a small number of keys:values from kwargs, extract<br>
them from the dict, and pass that on to another method:<br>
<br>
fnord = kwargs.pop('fnord', 'default')<br>
wibble = kwargs.pop('wibble', 42)<br>
super().spam(a, b, **kwargs)<br>
<br>
<br>
I don't have a concise syntax for this use-case, and yours won't work<br>
either. There's no way to supply defaults, nor can you list *all* the<br>
keys because you don't know what they will be. (The caller can provide<br>
arbitrary keyword arguments.)<br></blockquote><div><span style="line-height:1.5"><br></span></div><div><span style="line-height:1.5">You're right, I haven't thought about defaults. Hmm. Tuple unpacking doesn't support defaults either, so I guess I'll let this one go as not appropriate for dict unpacking.</span></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I think your syntax is too verbose and repetitive for the simple case.<br></blockquote><div><br></div><div>It's no more repetitive than str.format with keyword arguments :-)</div></div></div>