Python Performance / Dict vs NamedTuple

Dict vs NamedTuple

By Marcelo Fernandes Aug 13, 2017

Proposal:

Given that I am comparing two ways of getting a value from a key, check which one has a better performance.

Comparative in timeit module

Comparing the time of getting the value of a key from both situations.

from timeit import timeit

setup_dict = """car = {"color": "blue", "brand": "nissan", "price": 25000, "horn": "buzz"}"""

setup_named_tuple = """
from collections import namedtuple
car_namedtuple = namedtuple('car', ['color', 'brand', 'price', 'horn'])
car = car_namedtuple(color='blue', brand='nissan', price=25000, horn="buzz")
"""

look_up_dict = """car['price']"""
look_up_namedtuple = """car.price"""

dict_time = timeit(stmt=look_up_dict, setup=setup_dict, number=1000000)
namedtuple_time = timeit(stmt=look_up_namedtuple, setup=setup_named_tuple, number=1000000)

dict_time, namedtuple_time
# (0.02292850100002397, 0.04342634799991174)

Dict seems to be two times faster than namedtuples when retrieving values from keys.


Comparing the time of declaring a dict vs declaring a namedtuple.

from timeit import timeit

setup_named_tuple = """
from collections import namedtuple
car_namedtuple = namedtuple('car', ['color', 'brand', 'price', 'horn'])
"""

declare_dict = """car = {"color": "blue", "brand": "nissan", "price": 25000, "horn": "buzz"}"""
declare_namedtuple = """car = car_namedtuple(color='blue', brand='nissan', price=25000, horn="buzz")"""

dict_time = timeit(stmt=declare_dict, number=100000)
namedtuple_time = timeit(stmt=declare_namedtuple, setup=setup_named_tuple, number=100000)

dict_time, namedtuple_time
# (0.010182354999869858, 0.05484836699997686)

Dict seems to be five times faster than namedtuples on declaration.

Comparative via dis: Disassembler for Python bytecode.

Comparing the declaration bytecode.

from collections import namedtuple
from dis import dis

car_namedtuple = namedtuple('car', ['color', 'brand', 'price', 'horn'])

def make_named_tuple(color, brand, price, horn):
    return car_namedtuple(color=color, brand=brand, price=price, horn=horn)


def make_dict(color, brand, price, horn):
    return {"color": color, "brand": brand, "price": price, "horn": horn}


dis(make_named_tuple)

#              2 LOAD_FAST                0 (color)
#              4 LOAD_FAST                1 (brand)
#              6 LOAD_FAST                2 (price)
#              8 LOAD_FAST                3 (horn)
#             10 LOAD_CONST               1 (('color', 'brand', 'price', 'horn'))
#             12 CALL_FUNCTION_KW         4
#             14 RETURN_VALUE

dis(make_dict)

#           0 LOAD_FAST                0 (color)
#              2 LOAD_FAST                1 (brand)
#              4 LOAD_FAST                2 (price)
#              6 LOAD_FAST                3 (horn)
#              8 LOAD_CONST               1 (('color', 'brand', 'price', 'horn'))
#             10 BUILD_CONST_KEY_MAP      4
#             12 RETURN_VALUE


They are pretty similar, the difference is that the BUILD_CONST_KEY_MAP call is much more performatic than CALL_FUNCTION_KW, once it is a built-in optimized function.


Notes