[Python-ideas] Different interface for namedtuple?

Arnaud Delobelle arnodel at gmail.com
Fri Mar 4 22:34:07 CET 2011

On 4 Mar 2011, at 07:17, Carl M. Johnson wrote:

> I've been following the discussion on the list about decorators for
> assignments and whatnot, and while I do think it would be interesting
> if there were some way to abstract what happens in the creation of
> classes and defs into a more generalizable structure, for the
> immediate use case of NamedTuple, wouldn't an interface something like
> this solve the DRY problem? --
> class Point(NewNamedTuple): x, y
> This interface couldn't have worked in Python 2.6 when namedtuple was
> introduced, but using the __prepare__ statement in Python 3, it's
> trivial to implement. As a bonus, NewNamedTuple could also support
> type checking with the following syntax:
> class Point(NewNamedTuple): x, y = int, int #or whatever the ABC is
> for int-like numbers
> In fact, since as it stands namedtuple is called "namedtuple" in
> lowercase, we could just camel case "NamedTuple" to collections
> instead of using the NewNamedTuple or whatever. Or, and I haven't done
> any research on this, it may also be possible to implement
> NewNamedTuple with backwards compatibility so it can also be used in
> the traditional way.

It reminds me that a while ago (I think at the time of python 2.4), before the introduction of namedtuple, I had my own implementation of a "struct" decorator to create named tuples that enforced DRY and didn't require any metaclass magic. It worked as follows.

>>> @struct
... def Point(x=0, y=0):
...     "Two dimensional point with x and y coordinates"
...     return x, y
>>> p = Point(1, 2)
>>> p
Point(1, 2)
>>> tuple(p)
(1, 2)
>>> p.x, p.y
(1, 2)
>>> type(p)
<class '__main__.Point'>
>>> Point.__doc__
'Two dimensional point with x and y coordinates'
>>> Point(y=3)
(0, 3)

As you can see it abused "def", which at the time was the only way to create decorable objects that were aware of their own name.  It was implemented as follows:

def struct(f):
    classname = f.__name__
    prop_names = f.func_code.co_varnames[:f.func_code.co_argcount]
    def _new(cls, *args, **kwargs):
        return tuple.__new__(cls, f(*args, **kwargs))
    def _repr(self):
        return '%s%s' % (type(self).__name__, tuple(self))
    def prop(i):
        return property(lambda self: self[i])
    attrs = {
        '__slots__': (),
        '__new__': _new,
        '__repr__': _repr,
        '__doc__': f.__doc__
    attrs.update((name, prop(i)) for i, name in enumerate(prop_names))
    return type(classname, (tuple,), attrs)


More information about the Python-ideas mailing list