Hacker News new | past | comments | ask | show | jobs | submit login

I'm probably doing it wrong but I measured exactly this yesterday and the dict version was faster:

    $ python -m timeit --setup "from collections import namedtuple; Point = namedtuple('Point', ['x', 'y']); p = Point(x=0, y=0)" "p.x + p.y"
    1000000 loops, best of 3: 0.284 usec per loop
vs.

    $ python -m timeit --setup "p = {'x': 0, 'y': 0}" "p['x'] + p['y']"
    10000000 loops, best of 3: 0.0737 usec per loop
Maybe the use isn't right because I agree with your belief that namedtuple is suppose to be more performant.



You should be creating a dict vs. a namedtuple instance once, then accessing it many, many times. What you're doing is creating a lot of dict vs. namedtuple instances, then accessing each one only once. That's mostly testing the instance creation time, not the field access time.


That code should only create the dict/namedtuple instance once, then access it many, many times.

The creation occurs in the --setup portion. The field accesses occur in the actual looping portion of the timeit code.


Ah, ok, I see, for some reason my browser wasn't showing the namedtuple code snippet right. Now I need to go look at the namedtuple code to see why accessing the fields by name is slower than accessing them by index.


Yep. Because the dictionary literal gets created via opcodes in the interpreter loop whereas the named tuple pays the price of calling a function and setting up an interpreter frame.


The --setup code (creating the namedtuple and dict) is only executed once.

The timed portion is simply the field accesses.


Here's a neat (and totally unpythonic) way to bring that down a bit:

    python -m timeit --setup "from collections import namedtuple; Point = namedtuple('Point', ['x', 'y']); p = Point(x=0, y=0); get_y = Point.y.fget; get_x = Point.x.fget" "get_x(p) + get_y(p)"


I think you're timing the import in there, too. Plus, creating an object of a class rather than using a literal will always be slower.


Does the --setup statement really get timed?

My reading of the docs[1] has always led me to believe that it doesn't. For example, "It is possible to provide a setup statement that is executed only once at the beginning"

[1]: http://docs.python.org/2/library/timeit.html


It doesn't get timed. You can quickly test this by adding an expensive operation to your setup and checking that it doesn't affect the resulting time.


Aaah, ok. I totally didn't read the --setup arg.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: