<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, Jul 17, 2017 at 11:24 PM, Tim Peters <span dir="ltr"><<a href="mailto:tim.peters@gmail.com" target="_blank">tim.peters@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">[Giampaolo Rodola' <<a href="mailto:g.rodola@gmail.com">g.rodola@gmail.com</a>>]<br>
> ....<br>
<span class="gmail-">> To be entirely honest, I'm not even sure why they need to be forcefully<br>
> declared upfront in the first place, instead of just having a first-class<br>
> function (builtin?) written in C:<br>
><br>
> >>> ntuple(x=1, y=0)<br>
> (x=1, y=0)<br>
><br>
> ...or even a literal as in:<br>
><br>
> >>> (x=1, y=0)<br>
> (x=1, y=0)<br>
<br>
</span>How do you propose that the resulting object T know that T.x is 1. T.y<br>
is 0, and T.z doesn't make sense?  </blockquote><div><br></div><div>I'm not sure I understand your concern. That's pretty much what PyStructSequence already does. </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">Declaring a namedtuple up front<br>
allows the _class_ to know that all of its instances map attribute "x"<br>
to index 0 and attribute "y" to index 1.  The instances know nothing<br>
about that on their own</blockquote><div><br></div><div><div class="gmail_extra">Hence why I was talking about a "(lightweight) anonymous tuple with named attributes". The primary use case for namedtuples is accessing values by name (obj.x). Personally I've always considered the upfront module-level declaration only an annoyance which unnecessarily pollutes the API and adds extra overhead. I typically end up putting all namedtuples in a private module:</div><div class="gmail_extra"><a href="https://github.com/giampaolo/psutil/blob/8b8da39e0c62432504fb5f67c418715aad35b291/psutil/_common.py#L156-L225">https://github.com/giampaolo/psutil/blob/8b8da39e0c62432504fb5f67c418715aad35b291/psutil/_common.py#L156-L225</a><br></div><div class="gmail_extra">...then import them from elsewhere and make sure they are not exposed publicly because the intermediate object returned by collections.namedtuple() is basically useless for the end-user. Also picking up a sensible name for the namedtuple is an annoyance and kinda weird. Consider this:</div><div class="gmail_extra"><div class="gmail_extra"><br></div><div class="gmail_extra">    from collections import namedtuple</div><div class="gmail_extra"><br></div><div class="gmail_extra">    Coordinates = namedtuple('coordinates', ['x', 'y'])</div><div class="gmail_extra"><br></div><div class="gmail_extra">    def get_coordinates():</div><div class="gmail_extra">        return Coordinates(10, 20)</div></div><div class="gmail_extra"><div><br></div><div>...vs. this:</div><div><br></div><div><div>    def get_coordinates():</div><div>        return ntuple(x=10, y=20)</div></div><div> <br></div><div>...or this:</div><div><br></div><div><div><div>    def get_coordinates():</div><div>        return (x=10, y=20)</div></div></div><div><br></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">If your `ntuple()` returns an object implementing its own<br>
mapping, it loses a primary advantage (0 memory overhead) of<br>
namedtuples.<br>
</blockquote><div><br></div><div>The extra memory overhead is a price I would be happy to pay considering that collections.namedtuple is considerably slower than a plain tuple. Other than the additional overhead on startup / import time, instantiation is 4.5x slower than a plain tuple:</div><div></div></div></div><div class="gmail_extra"><div><div></div></div><div><br></div><div><div><div>    $ python3.7 -m timeit -s "from collections import namedtuple; nt = namedtuple('xxx', ('x', 'y'))" "nt(1, 2)"</div><div>    1000000 loops, best of 5: 313 nsec per loop</div><div><br></div><div>    $ python3.7 -m timeit "tuple((1, 2))"</div><div>    5000000 loops, best of 5: 68.4 nsec per loop</div><div><br></div><div>...and name access is 2x slower than index access:</div><div><br></div><div>    $ python3.7 -m timeit -s "from collections import namedtuple; nt = namedtuple('xxx', ('x', 'y')); x = nt(1, 2)" "x.x"</div><div>    5000000 loops, best of 5: 41.9 nsec per loop</div><div><br></div><div>    $ python3.7 -m timeit -s "from collections import namedtuple; nt = namedtuple('xxx', ('x', 'y')); x = nt(1, 2)" "x[0]"</div><div>    10000000 loops, best of 5: 20.2 nsec per loop</div></div></div><div><div>    $ python3.7 -m timeit -s "x = (1, 2)" "x[0]"</div><div>    10000000 loops, best of 5: 20.5 nsec per loop</div></div><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div>Giampaolo - <a href="http://grodola.blogspot.com" target="_blank">http://grodola.blogspot.com</a></div><div><br></div></div></div>
</div></div>