[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)
--
Arnaud
More information about the Python-ideas
mailing list