Improvements to NamedTuple's implementation, tests, and documentation

This commit is contained in:
Raymond Hettinger 2007-05-19 01:11:16 +00:00
parent 6290305e67
commit 5a41daf096
3 changed files with 36 additions and 25 deletions

View file

@ -24,30 +24,29 @@ def NamedTuple(typename, s):
"""
field_names = s.split()
nargs = len(field_names)
assert ''.join(field_names).replace('_', '').isalpha() # protect against exec attacks
argtxt = ', '.join(field_names)
reprtxt = ', '.join('%s=%%r' % name for name in field_names)
template = '''class %(typename)s(tuple):
'%(typename)s(%(argtxt)s)'
__slots__ = ()
def __new__(cls, %(argtxt)s):
return tuple.__new__(cls, (%(argtxt)s,))
def __repr__(self):
return '%(typename)s(%(reprtxt)s)' %% self
''' % locals()
for i, name in enumerate(field_names):
template += '\t%s = property(itemgetter(%d))\n' % (name, i)
m = dict(itemgetter=_itemgetter)
exec template in m
result = m[typename]
if hasattr(_sys, '_getframe'):
result.__module__ = _sys._getframe(1).f_globals['__name__']
return result
def __new__(cls, *args, **kwds):
if kwds:
try:
args += tuple(kwds[name] for name in field_names[len(args):])
except KeyError, name:
raise TypeError('%s missing required argument: %s' % (typename, name))
if len(args) != nargs:
raise TypeError('%s takes exactly %d arguments (%d given)' % (typename, nargs, len(args)))
return tuple.__new__(cls, args)
repr_template = '%s(%s)' % (typename, ', '.join('%s=%%r' % name for name in field_names))
m = dict(vars(tuple)) # pre-lookup superclass methods (for faster lookup)
m.update(__doc__= '%s(%s)' % (typename, ', '.join(field_names)),
__slots__ = (), # no per-instance dict (so instances are same size as tuples)
__new__ = __new__,
__repr__ = lambda self, _format=repr_template.__mod__: _format(self),
__module__ = _sys._getframe(1).f_globals['__name__'],
)
m.update((name, property(_itemgetter(index))) for index, name in enumerate(field_names))
return type(typename, (tuple,), m)
if __name__ == '__main__':