blob: 4a860dd0c0cfa4b48561691753ecf160cd5c3800 [file] [log] [blame]
Raymond Hettingerc37e5e02007-03-01 06:16:43 +00001__all__ = ['deque', 'defaultdict', 'NamedTuple']
Raymond Hettingereb979882007-02-28 18:37:52 +00002
3from _collections import deque, defaultdict
Raymond Hettingerc37e5e02007-03-01 06:16:43 +00004from operator import itemgetter as _itemgetter
5import sys as _sys
6
7def NamedTuple(typename, s):
8 """Returns a new subclass of tuple with named fields.
9
10 >>> Point = NamedTuple('Point', 'x y')
11 >>> Point.__doc__ # docstring for the new class
12 'Point(x, y)'
13 >>> p = Point(11, y=22) # instantiate with positional args or keywords
14 >>> p[0] + p[1] # works just like the tuple (11, 22)
15 33
16 >>> x, y = p # unpacks just like a tuple
17 >>> x, y
18 (11, 22)
19 >>> p.x + p.y # fields also accessable by name
20 33
21 >>> p # readable __repr__ with name=value style
22 Point(x=11, y=22)
23
24 """
25
26 field_names = s.split()
Raymond Hettinger767debb2007-05-21 16:40:10 +000027 if not ''.join([typename] + field_names).replace('_', '').isalnum():
Raymond Hettinger0d6a8cc2007-05-21 08:13:35 +000028 raise ValueError('Type names and field names can only contain alphanumeric characters and underscores')
Raymond Hettinger5a41daf2007-05-19 01:11:16 +000029 argtxt = ', '.join(field_names)
30 reprtxt = ', '.join('%s=%%r' % name for name in field_names)
31 template = '''class %(typename)s(tuple):
32 '%(typename)s(%(argtxt)s)'
33 __slots__ = ()
34 def __new__(cls, %(argtxt)s):
35 return tuple.__new__(cls, (%(argtxt)s,))
36 def __repr__(self):
37 return '%(typename)s(%(reprtxt)s)' %% self
38 ''' % locals()
39 for i, name in enumerate(field_names):
Raymond Hettingerf3241a32007-05-19 01:50:11 +000040 template += '\n %s = property(itemgetter(%d))\n' % (name, i)
Raymond Hettinger5a41daf2007-05-19 01:11:16 +000041 m = dict(itemgetter=_itemgetter)
42 exec template in m
43 result = m[typename]
44 if hasattr(_sys, '_getframe'):
45 result.__module__ = _sys._getframe(1).f_globals['__name__']
46 return result
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000047
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000048
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000049
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000050
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000051
52
53if __name__ == '__main__':
54 # verify that instances are pickable
55 from cPickle import loads, dumps
56 Point = NamedTuple('Point', 'x y')
57 p = Point(x=10, y=20)
58 assert p == loads(dumps(p))
59
60 import doctest
61 TestResults = NamedTuple('TestResults', 'failed attempted')
62 print TestResults(*doctest.testmod())