NamedTuple is a tuple subclass that allows its elements to be named. Elements can be accessed by index and by name.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class NamedTuple(tuple):
"""Builds a tuple with elements named and indexed.
A NamedTuple is constructed with a sequence of (name, value) pairs;
the values can then be obtained by looking up the name or the value.
"""
def __new__(cls, seq):
return tuple.__new__(cls, [val for name,val in seq])
def __init__(self, seq):
tuple.__init__(self)
tuple.__setattr__(self, "_names", dict(zip([name for name,val in seq], range(len(seq)))))
def __getattr__(self, name):
try:
return tuple.__getitem__(self, self.__dict__["_names"][name])
except KeyError:
raise AttributeError, "object has no attribute named '%s'" % name
def __setattr__(self, name, value):
raise TypeError, "'NamedTuple' object has only read-only attributes (assign to .%s)" % name
|
A common usage of tuples is to represent aggregations of heterogenous data, as a kind of anonymous data structure. The built-in tuple type only allows the elements to be accessed by their indices; this leads to a loss of clarity: seeing x[3] in code is less clear than x.middlename, for example.
The NamedTuple class allows construction of tuples with named elements. These elements can then be accessed by index or by name, as convenient. For example:
names = ("name", "age", "height")
person1 = NamedTuple(zip(names, ["James", "26", "185"]))
person2 = NamedTuple(zip(names, ["Sarah", "24", "170"]))
print person1.name
for i,name in enumerate(names): print name, ":", person2[i]
Because NamedTuple is a subclass of tuple, all the standard tuple methods will work on it as usual. This provides the convenience of tuples with the clarity of named elements.
Kudos and a Mod. Andrew, this is great! I started working with it and came up with a few mods. Unfortunately I don't know how to appropriately paste code in the comments yet, so I submitted a new recipe (#303770) that details the mods I made. I hope you'll check it out and let me know what you think. Basically, I moved the _names dict to a 'base' class so that all derivations don't need to specify the attribute names at instantiation time. This helps to reduce the clutter when instantiating the tuples. Thanks for sharing!