<div dir="ltr"><div class="gmail_default" style="font-family:monospace,monospace"><span style="font-family:arial,sans-serif">On Wed, Jul 26, 2017 at 8:10 PM, Steven D'Aprano </span><span dir="ltr" style="font-family:arial,sans-serif"><<a href="mailto:steve@pearwood.info" target="_blank">steve@pearwood.info</a>></span><span style="font-family:arial,sans-serif"> wrote:</span><br></div><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-">On Thu, Jul 27, 2017 at 02:05:47AM +1000, Nick Coghlan wrote:<br></span><span class="gmail-">> >>> from collections import OrderedDict<br>
> >>> OrderedDict(x=1, y=2)<br>
> OrderedDict([('x', 1), ('y', 2)])<br>
> >>> OrderedDict(y=2, x=1)<br>
> OrderedDict([('y', 2), ('x', 1)])<br>
><br>
> In this case, the "order matters" expectation is informed by the<br>
> nature of the constructor being called: it's an *ordered* dict, so the<br>
> constructor argument order matters.<br>
<br>
</span>I don't think that's a great analogy. There's no real equivalent of<br>
packing/unpacking OrderedDicts by position to trip us up here. It is<br>
better to think of OrderedDicts as "order-preserving dicts" rather than<br>
"dicts where the order matters". Yes, it does matter, in a weak sense. </blockquote><div><br></div><div><div class="gmail_default" style="font-family:monospace,monospace">Careful here, this is misleading. What you say applies to the normal dict since 3.6, which now *preserves* order. But in OrderedDict, order matters in quite a strong way:</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">od1 = OrderedDict(a=1, b=2) </div><div class="gmail_default" style="font-family:monospace,monospace">od2 = OrderedDict(b=2, a=1) # (kwargs order obviously matters)</div><div class="gmail_default" style="font-family:monospace,monospace"></div><div class="gmail_default" style="font-family:monospace,monospace">od1 == od2 # gives False !!</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">od1 == dict(a=1, b=2) # gives True</div><div class="gmail_default" style="font-family:monospace,monospace">od2 == dict(a=1, b=2) # gives True</div><div class="gmail_default" style="font-family:monospace,monospace">od1 == OrderedDict(a=1, b=2) # gives True <br></div><br></div><div><div class="gmail_default" style="font-family:monospace,monospace">I also think this is how OrderedDict *should* behave to earn its name. It's great that we now also have an order-*preserving* dict, because often you want that, but still dict(a=!, b=2) == dict(b=2, a=1).</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">But not in the important sense of binding values to keys:<br>
<br>
py> from collections import OrderedDict<br>
py> a = OrderedDict([('spam', 1), ('eggs', 2)])<br>
py> b = OrderedDict([('eggs', -1), ('spam', 99)])<br>
py> a.update(b)<br>
py> a<br>
OrderedDict([('spam', 99), ('eggs', -1)])<br>
<br>
update() has correctly bound 99 to key 'spam', even though the keys are<br>
in the wrong order. The same applies to dict unpacking:<br>
<br></blockquote><div><br></div><div><div class="gmail_default" style="font-family:monospace,monospace">The reason for this is that the order is determined by the first binding, not by subsequent updates to already-existing keys. </div></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
a.update(**b)<br>
<br></blockquote><div><div class="gmail_default" style="font-family:monospace,monospace"></div><div class="gmail_default" style="font-family:monospace,monospace">Unpacking by name is still ordered in a.update(**b), but the update order does not matter, because keys 'spam' and 'eggs' already exist.</div></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
In contrast, named tuples aren't just order-preserving. The field order<br>
is part of their definition, and tuple unpacking honours the field<br>
order, not the field names. While we can't update tuples in place, we<br>
can and often do unpack them into variables. When we do, we need to know<br>
the field order:<br>
<br></blockquote><div><br></div><div><div class="gmail_default" style="font-family:monospace,monospace">I hope this was already clear to people in the discussion, but in case not, thanks for clarifying.</div></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
flavour, charge, mass, spin, isospin, hypercharge = mytuple<br>
<br>
but the risk is that the field order may not be what we expect unless we<br>
are scrupulously careful to *always* call ntuple(...) with the arguments<br>
in the same order.<br>
<span class="gmail-HOEnZb"><font color="#888888"><br></font></span></blockquote><div><br></div><div><div class="gmail_default" style="font-family:monospace,monospace">This is indeed among the reasons why the tuple api is desirable mostly for backwards compatibility in existing functions, as pointed out early in this thread. New functions will hopefully use something with only attribute access to the values, unless there is a clear reason to also have integer indexing and unpacking by order.</div></div><div><br></div><div><div class="gmail_default" style="font-family:monospace,monospace">-- Koos</div></div><div><br></div></div><div><br></div>-- <br><div class="gmail_signature">+ Koos Zevenhoven + <a href="http://twitter.com/k7hoven" target="_blank">http://twitter.com/k7hoven</a> +</div>
</div></div>