<div dir="ltr"><div dir="ltr"><div dir="ltr">On Sat, Jan 26, 2019 at 10:31 AM Steven D'Aprano <<a href="mailto:steve@pearwood.info">steve@pearwood.info</a>> wrote:<br></div><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">In what way is it worse, given that returning a namedtuple with named <br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
fields is backwards compatible with returning a regular tuple? We can <br>
have our cake and eat it too.<br>Unless the caller does a type-check, there is no difference. Sequence <br>
unpacking will still work, and namedtuples unlike regular tuples can <br>
support optional attributes.<br></blockquote><div><br></div><div>I suppose the one difference is where someone improperly relies on tuple unpacking.</div><div><br></div><div>Old version:</div><div><br></div></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div class="gmail_quote"><div><font face="monospace, monospace">def myfun():</font></div></div><div class="gmail_quote"><div><font face="monospace, monospace">    # ...</font></div></div><div class="gmail_quote"><div><font face="monospace, monospace">    return a, b, c</font></div></div><div class="gmail_quote"><div><font face="monospace, monospace"><br></font></div></div><div class="gmail_quote"><div><font face="monospace, monospace"># Call site</font></div><div><font face="monospace, monospace">val1, val2, val3 = myfun()</font></div></div></blockquote><div class="gmail_quote"><div><br></div><div>New version:</div><div> </div></div></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div class="gmail_quote"><div><div class="gmail_quote"><div><font face="monospace, monospace">def myfun():</font></div></div></div></div></div><div><div class="gmail_quote"><div><div class="gmail_quote"><div><font face="monospace, monospace">    # ...</font></div></div></div></div></div><div><div class="gmail_quote"><div><div class="gmail_quote"><div><font face="monospace, monospace">    return a, b, c, d</font></div></div></div></div></div></blockquote><div dir="ltr"><div class="gmail_quote"><div><div class="gmail_quote"><br class="gmail-Apple-interchange-newline"></div></div><div>Now the call site will get "ValueError: too many values to unpack".  Namedtuples don't solve this problem, of course.  But they don't make anything worse either.</div><div><br></div><div>The better approach, of course, is to document the API as only using attribute access, not positional.  I reckon dataclasses from the start could address that concern... but so can documentation alone.  E.g.:</div><div><br></div><div>Old version (improved):</div><div><br></div><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div class="gmail_quote"><div><font face="monospace, monospace">def myfun():</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div class="gmail_quote"><div><font face="monospace, monospace">    mydata = namedtuple("mydata", "a b c")</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div class="gmail_quote"><div><font face="monospace, monospace">    # ...</font></div></div><div class="gmail_quote"><div><font face="monospace, monospace">    return mydata(a, b, c)</font></div></div><div class="gmail_quote"><div><font face="monospace, monospace"><br></font></div></div><div class="gmail_quote"><div><font face="monospace, monospace"># Call site</font></div><div><font face="monospace, monospace">ret = myfun()</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div class="gmail_quote"><div><font face="monospace, monospace">val1, val2, val3 = ret.a, ret.b, ret.c</font></div></div></blockquote><div class="gmail_quote"><br></div><div class="gmail_quote">New version (improved)</div></div><div class="gmail_quote"><br></div><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div class="gmail_quote"><div><font face="monospace, monospace">def myfun():</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div class="gmail_quote"><div><font face="monospace, monospace">    mydata = namedtuple("mydata", "a b c d e")</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div class="gmail_quote"><div><font face="monospace, monospace">    # ...</font></div></div><div class="gmail_quote"><div><font face="monospace, monospace">    return mydata(a, b, c, d, e)</font></div></div><div class="gmail_quote"><br class="gmail-Apple-interchange-newline"></div></blockquote></div><div>Now the call site is completely happy with no changes (assuming it doesn't need to care about what values 'ret.d' or 'ret.e' contain... but presumably those extra values are optional in some way.</div><div><br></div><div>Moreover, we are even perfectly fine if we had created <font face="monospace, monospace">namedtuple("mydata", "e d c b a")</font><font face="arial, helvetica, sans-serif"> for some reason, completely changing the positions of all the named attributes in the improved namedtuple.</font></div><div> </div></div>-- <br><div dir="ltr" class="gmail_signature">Keeping medicines from the bloodstreams of the sick; food <br>from the bellies of the hungry; books from the hands of the <br>uneducated; technology from the underdeveloped; and putting <br>advocates of freedom in prisons.  Intellectual property is<br>to the 21st century what the slave trade was to the 16th.<br></div></div></div>