<div dir="auto"><div>Indeed! I promise to use dataclass next time I find myself about to use namedtuple. :-)</div><div dir="auto"><br></div><div dir="auto">I'm pretty sure that virtually all my uses will allow that.<br><br><div class="gmail_quote" dir="auto"><div dir="ltr">On Sat, Jan 26, 2019, 1:09 PM Eric V. Smith <<a href="mailto:eric@trueblade.com">eric@trueblade.com</a> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
<br>
On 1/26/2019 12:30 PM, David Mertz wrote:<br>
> On Sat, Jan 26, 2019 at 10:31 AM Steven D'Aprano <<a href="mailto:steve@pearwood.info" target="_blank" rel="noreferrer">steve@pearwood.info</a> <br>
> <mailto:<a href="mailto:steve@pearwood.info" target="_blank" rel="noreferrer">steve@pearwood.info</a>>> wrote:<br>
> <br>
> In what way is it worse, given that returning a namedtuple with named<br>
> <br>
> 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>
> <br>
> <br>
> I suppose the one difference is where someone improperly relies on tuple <br>
> unpacking.<br>
> <br>
> Old version:<br>
> <br>
> def myfun():<br>
> # ...<br>
> return a, b, c<br>
> <br>
> # Call site<br>
> val1, val2, val3 = myfun()<br>
> <br>
> <br>
> New version:<br>
> <br>
> def myfun():<br>
> # ...<br>
> return a, b, c, d<br>
> <br>
> <br>
> Now the call site will get "ValueError: too many values to unpack". <br>
> Namedtuples don't solve this problem, of course. But they don't make <br>
> anything worse either.<br>
> <br>
> The better approach, of course, is to document the API as only using <br>
> attribute access, not positional. I reckon dataclasses from the start <br>
> could address that concern... but so can documentation alone. E.g.:<br>
> <br>
> Old version (improved):<br>
> <br>
> def myfun():<br>
> <br>
> mydata = namedtuple("mydata", "a b c")<br>
> <br>
> # ...<br>
> return mydata(a, b, c)<br>
> <br>
> # Call site<br>
> ret = myfun()<br>
> <br>
> val1, val2, val3 = ret.a, ret.b, ret.c<br>
> <br>
> <br>
> New version (improved)<br>
> <br>
> def myfun():<br>
> <br>
> mydata = namedtuple("mydata", "a b c d e")<br>
> <br>
> # ...<br>
> return mydata(a, b, c, d, e)<br>
> <br>
> Now the call site is completely happy with no changes (assuming it <br>
> doesn't need to care about what values 'ret.d' or 'ret.e' contain... but <br>
> presumably those extra values are optional in some way.<br>
> <br>
> Moreover, we are even perfectly fine if we had created <br>
> namedtuple("mydata", "e d c b a") for some reason, completely changing <br>
> the positions of all the named attributes in the improved namedtuple.<br>
<br>
Preventing this automatic unpacking (and preventing iteration in <br>
general) was one of the motivating factors for dataclasses: <br>
<a href="https://www.python.org/dev/peps/pep-0557/#id47" rel="noreferrer noreferrer" target="_blank">https://www.python.org/dev/peps/pep-0557/#id47</a><br>
<br>
Eric<br>
</blockquote></div></div></div>