Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is accessing a namedtuple by field name slower than accessing a class's member variable?

We were doing some experiments to compare the access time in classes and named tuples and observed something strange.

import time
from collections import namedtuple as namedtuple

class myclass(object):

  def __init__(self, _name, _dob, _value):
    self.name = _name
    self.dob = _dob
    self.value = _value

randomperson1 = myclass( 'randomperson', 10102000, 10.45 )

person = namedtuple( 'person', 'name dob value' )
randomperson2 = person( 'randomperson', 10102000, 10.45) 

While using timeit of ipython, the following was observed:

%timeit randomperson1.name,randomperson1.value,randomperson1.dob
10000000 loops, best of 3: 125 ns per loop

%timeit randomperson2.name,randomperson2.value,randomperson2.dob
1000000 loops, best of 3: 320 ns per loop

%timeit randomperson2[0],randomperson2[1],randomperson2[2]
10000000 loops, best of 3: 127 ns per loop

Why's accessing a namedtuple by field name so much slower than accessing a class's member variable? Is there any way to speed this up?

like image 325
web_ninja Avatar asked Oct 19 '25 14:10

web_ninja


1 Answers

That's because in namedtuple attributes name, value, dob are not simple attributes on the instance. They actually are turned into something more complicated

collections.py

_field_template = '''\
    {name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}')
'''

e.g.

dob = property(itemgetter(2), doc='Alias for field number 2')

So as you can see there are additional layers over it. People who created namedtuple decided that they want consistency with memory efficiency at the cost of CPU efficiency. And that is the reason.

This can be easily observed when you create your own custom class emulating this:

from operator import itemgetter

class CustomTuple(tuple):
    my_attr = property(itemgetter(0))

test_tuple = CustomTuple([1])

and now measure access to test_tuple.my_attr. You should get pretty much the same results.

like image 62
freakish Avatar answered Oct 22 '25 04:10

freakish