Skip to content

Instantly share code, notes, and snippets.

@wolph
Last active May 10, 2024 13:02
Show Gist options
  • Save wolph/02fae0b20b914354734aaac01c06d23b to your computer and use it in GitHub Desktop.
Save wolph/02fae0b20b914354734aaac01c06d23b to your computer and use it in GitHub Desktop.
Benchmark namedtuple vs dataclass vs dict
import sys
import enum
import math
import random
import timeit
import typing
import dataclasses
import collections
repeat = 5
number = 1000
N = 5000
class PointTuple(typing.NamedTuple):
x: int
y: int
z: int
@dataclasses.dataclass
class PointDataclass:
x: int
y: int
z: int
@dataclasses.dataclass(slots=True)
class PointDataclassSlots:
x: int
y: int
z: int
class PointObject:
__slots__ = 'x', 'y', 'z'
x: int
y: int
z: int
def test_namedtuple_attr():
point = PointTuple(1234, 5678, 9012)
for i in range(N):
x, y, z = point.x, point.y, point.z
def test_namedtuple_index():
point = PointTuple(1234, 5678, 9012)
for i in range(N):
x, y, z = point
def test_namedtuple_unpack():
point = PointTuple(1234, 5678, 9012)
for i in range(N):
x, *y = point
def test_dataclass():
point = PointDataclass(1234, 5678, 9012)
for i in range(N):
x, y, z = point.x, point.y, point.z
def test_dataclass_slots():
point = PointDataclassSlots(1234, 5678, 9012)
for i in range(N):
x, y, z = point.x, point.y, point.z
def test_dict():
point = dict(x=1234, y=5678, z=9012)
for i in range(N):
x, y, z = point['x'], point['y'], point['z']
def test_slots():
point = PointObject()
point.x = 1234
point.y = 5678
point.z = 9012
for i in range(N):
x, y, z = point.x, point.y, point.z
class PointEnum(enum.Enum):
x = 1
y = 2
z = 3
def test_enum_attr():
point = PointEnum
for i in range(N):
x, y, z = point.x, point.y, point.z
def test_enum_call():
point = PointEnum
for i in range(N):
x, y, z = point(1), point(2), point(3)
def test_enum_item():
point = PointEnum
for i in range(N):
x, y, z = point['x'], point['y'], point['z']
if __name__ == '__main__':
tests = [
test_namedtuple_attr,
test_namedtuple_index,
test_namedtuple_unpack,
test_dataclass,
test_dataclass_slots,
test_dict,
test_slots,
test_enum_attr,
test_enum_call,
test_enum_item,
]
print(f'Running tests {repeat} times with {number} calls.')
print(f'Using {N} iterations in the loop')
results = collections.defaultdict(lambda: math.inf)
for i in range(repeat):
# Shuffling tests to prevent skewed results due to CPU boosting or
# thermal throttling
random.shuffle(tests)
print(f'Run {i}:', end=' ')
for t in tests:
name = t.__name__
print(name, end=', ')
sys.stdout.flush()
timer = timeit.Timer(f'{name}()', f'from __main__ import {name}')
results[name] = min(results[name], timer.timeit(number))
print()
for name, result in sorted(results.items(), key=lambda x: x[::-1]):
print(f'{name:30} {result:.3f}s')
@wolph
Copy link
Author

wolph commented Jan 7, 2023

I've also added a dataclass with slots with this version

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment