Created
December 20, 2016 19:17
-
-
Save grantjenks/a06da0db18826be1176c31c95a6ee572 to your computer and use it in GitHub Desktop.
Performance Comparison of namedtuple, namedlist, and recordclass
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
#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 µsAccess: (lambda used, can be not so valid)
namedtuple: 217 ns
namedlist: 186 ns
recordclass: 180 ns
structclass: 186 ns
Record: 183 nsSize:
namedtuple: 52
namedlist: 48
recordclass: 36
structclass: 32
Record: 48
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
Output:
My advice is to prefer the
Record
recipe above. Thirty lines of code and it pretty prints, pickles, copies, and unpacks. You can also easily customize to your liking.