Skip to content

Instantly share code, notes, and snippets.

@grantjenks
Created December 20, 2016 19:17
Show Gist options
  • Save grantjenks/a06da0db18826be1176c31c95a6ee572 to your computer and use it in GitHub Desktop.
Save grantjenks/a06da0db18826be1176c31c95a6ee572 to your computer and use it in GitHub Desktop.
Performance Comparison of namedtuple, namedlist, and recordclass
import sys
class Record(object):
__slots__ = ()
def __init__(self, *args):
assert len(self.__slots__) == len(args)
for field, value in zip(self.__slots__, args):
setattr(self, field, value)
def __getitem__(self, index):
return getattr(self, self.__slots__[index])
def __len__(self):
return len(self.__slots__)
def __eq__(self, that):
if not isinstance(that, type(self)):
return NotImplemented
return all(item == iota for item, iota in zip(self, that))
def __repr__(self):
args = ', '.join(repr(item) for item in self)
return '%s(%s)' % (type(self).__name__, args)
def __getstate__(self):
return tuple(self)
def __setstate__(self, state):
self.__init__(*state)
from collections import namedtuple
from namedlist import namedlist
from recordclass import recordclass
NTTest = namedtuple('NTTest', 'a b c d e f')
NLTest = namedlist('NLTest', 'a b c d e f')
RCTest = recordclass('RCTest', 'a b c d e f')
class RETest(Record):
__slots__ = 'a', 'b', 'c', 'd', 'e', 'f'
nttest = NTTest(1, 2, 3, 4, 5, 6)
nltest = NLTest(1, 2, 3, 4, 5, 6)
rctest = RCTest(1, 2, 3, 4, 5, 6)
retest = RETest(1, 2, 3, 4, 5, 6)
print 'Attribute Access'
print 'namedtuple'
%timeit nttest.c
print 'namedlist'
%timeit nltest.c
print 'recordclass'
%timeit rctest.c
print 'Record'
%timeit retest.c
print 'Object Size'
print 'namedtuple'
print sys.getsizeof(nttest)
print 'namedlist'
print sys.getsizeof(nltest)
print 'recordclass'
print sys.getsizeof(rctest)
print 'Record'
print sys.getsizeof(retest)
@C0oo1D
Copy link

C0oo1D commented May 5, 2019

#python 3.7
import sys
from lib import exec_time  # based on get min time of timeit.Timer and partial().repeat()

from collections import namedtuple
from namedlist import namedlist
from recordclass import recordclass, structclass


class Record(object):
    __slots__ = ()

    def __init__(self, *args):
        assert len(self.__slots__) == len(args)
        for field, value in zip(self.__slots__, args):
            setattr(self, field, value)

    def __getitem__(self, index):
        return getattr(self, self.__slots__[index])

    def __len__(self):
        return len(self.__slots__)

    def __eq__(self, that):
        if not isinstance(that, type(self)):
            return NotImplemented
        return all(item == iota for item, iota in zip(self, that))

    def __repr__(self):
        args = ', '.join(repr(item) for item in self)
        return '%s(%s)' % (type(self).__name__, args)

    def __getstate__(self):
        return tuple(self)

    def __setstate__(self, state):
        self.__init__(*state)


params_count = 6
fields = tuple(hex(_)[1:] for _ in range(params_count))
args = tuple(range(params_count))

NTTest = namedtuple('NTTest', fields)
NLTest = namedlist('NLTest', fields)
RCTest = recordclass('RCTest', fields)
SCTest = structclass('SCTest', fields)


class RETest(Record):
    __slots__ = fields


print('\nCreate:')
print(f'\tnamedtuple: {exec_time(NTTest, *args)}')
print(f'\tnamedlist: {exec_time(NLTest, *args)}')
print(f'\trecordclass: {exec_time(RCTest, *args)}')
print(f'\tstructclass: {exec_time(SCTest, *args)}')
print(f'\tRecord: {exec_time(RETest, *args)}')


nttest = NTTest(*args)
nltest = NLTest(*args)
rctest = RCTest(*args)
sctest = SCTest(*args)
retest = RETest(*args)

print('\nAccess:')
print(f'\tnamedtuple: {exec_time(lambda: nttest.x1)}')
print(f'\tnamedlist: {exec_time(lambda: nltest.x1)}')
print(f'\trecordclass: {exec_time(lambda: rctest.x1)}')
print(f'\tstructclass: {exec_time(lambda: sctest.x1)}')
print(f'\tRecord: {exec_time(lambda: retest.x1)}')

print('\nSize:')
print(f'\tnamedtuple: {sys.getsizeof(nttest)}')
print(f'\tnamedlist: {sys.getsizeof(nltest)}')
print(f'\trecordclass: {sys.getsizeof(rctest)}')
print(f'\tstructclass: {sys.getsizeof(sctest)}')
print(f'\tRecord: {sys.getsizeof(retest)}')

Create:
namedtuple: 496 ns
namedlist: 4.07 µs
recordclass: 422 ns
structclass: 509 ns
Record: 1.94 µs

Access: (lambda used, can be not so valid)
namedtuple: 217 ns
namedlist: 186 ns
recordclass: 180 ns
structclass: 186 ns
Record: 183 ns

Size:
namedtuple: 52
namedlist: 48
recordclass: 36
structclass: 32
Record: 48

@C0oo1D
Copy link

C0oo1D commented May 6, 2019

print('\nAccess:')
print(f'\tnamedtuple: {exec_time(lambda: (nttest.x0, nttest.x1, nttest.x2, nttest.x3, nttest.x4, nttest.x5))}')
print(f'\tnamedlist: {exec_time(lambda: (nltest.x0, nltest.x1, nltest.x2, nltest.x3, nltest.x4, nltest.x5))}')
print(f'\trecordclass: {exec_time(lambda: (rctest.x0, rctest.x1, rctest.x2, rctest.x3, rctest.x4, rctest.x5))}')
print(f'\tstructclass: {exec_time(lambda: (sctest.x0, sctest.x1, sctest.x2, sctest.x3, sctest.x4, sctest.x5))}')
print(f'\tRecord: {exec_time(lambda: (retest.x0, retest.x1, retest.x2, retest.x3, retest.x4, retest.x5))}')

Access:
namedtuple: 621 ns
namedlist: 496 ns
recordclass: 434 ns
structclass: 481 ns
Record: 465 ns

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