blob: 2cf9fe84c797f967aa1e30d274978ca42210c51c [file] [log] [blame]
Guido van Rossumd8faa362007-04-27 19:54:29 +00001__all__ = ['deque', 'defaultdict', 'NamedTuple']
2
3from _collections import deque, defaultdict
4from 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()
Guido van Rossumd59da4b2007-05-22 18:11:13 +000027 if not ''.join([typename] + field_names).replace('_', '').isalnum():
28 raise ValueError('Type names and field names can only contain alphanumeric characters and underscores')
29 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):
40 template += '\n %s = property(itemgetter(%d))\n' % (name, i)
41 m = dict(itemgetter=_itemgetter)
42 exec(template, m)
43 result = m[typename]
44 if hasattr(_sys, '_getframe'):
45 result.__module__ = _sys._getframe(1).f_globals['__name__']
46 return result
Guido van Rossumd8faa362007-04-27 19:54:29 +000047
Guido van Rossumd8faa362007-04-27 19:54:29 +000048
Guido van Rossumd8faa362007-04-27 19:54:29 +000049
Guido van Rossumd8faa362007-04-27 19:54:29 +000050
51
52if __name__ == '__main__':
53 # verify that instances are pickable
54 from cPickle import loads, dumps
55 Point = NamedTuple('Point', 'x y')
56 p = Point(x=10, y=20)
57 assert p == loads(dumps(p))
58
59 import doctest
60 TestResults = NamedTuple('TestResults', 'failed attempted')
61 print(TestResults(*doctest.testmod()))