namedtuple() subclasses again
Hello, Another thoughts (and use cases) about namedtuple-DRY-matter and (what is more important) subclassing namedtuple() classes: Quite often I need to create my own named tuple class(es) with some additional methods or modifications of existing ones (most often: a custom version of __repr__()). Now I must write something like: _MyNamedTupleBase = namedtuple('MyNamedTuple', ('one_field', 'another_field', 'and_another_one')) class MyNamedTuple(_MyNamedTupleBase): def __repr__(self): "My sophisticated __repr__()" # and e.g. some new methods... ...or: class MyNamedTuple(namedtuple('MyNamedTuple', ('one_field', 'another_field', 'and_another_one'))): def __repr__(self): "My sophisticated __repr__()" # and e.g. some new methods... It would be very nice to be able to do it in such a way: class MyNamedTuple(namedtuple.abc): _fields = ( 'one_field', 'another_field', 'and_another_one', ) def __repr__(self): "My sophisticated __repr__()" # and e.g. some new methods... ...and especially: class MyAbstractNamedTuple(namedtuple.abc): def __repr__(self): "My sophisticated __repr__()" # and e.g. some new methods... class MyNamedTupleA(MyAbstractNamedTuple): _fields = 'a b c' class MyNamedTupleB(MyAbstractNamedTuple): _fields = ( 'one_field', 'another_field', 'and_another_one', ) (Please note that _fields is a part of the public API of named tuples). Implementation would be easy to explain (and to do; actually I have an outline in my head). The type (metaclass) of namedtuple.abc would be a subclass of abc.ABCMeta and would also act (by ABC registration mechanism) as an abstract base for all named tuples and structsequences like sys.version_info. So all these expressions would be True:
isinstance(namedtuple('Foo', 'x y z'), namedtuple.abc) isinstance(sys.version_info, namedtuple.abc)
And obviously:
isinstance(MyNamedTuple, namedtuple.abc) # referiring to the above examples
What do you think about the idea? Regards. *j
Sorry, mistake. Jan Kaliszewski dixit (2011-03-25, 15:06):
isinstance(namedtuple('Foo', 'x y z'), namedtuple.abc) isinstance(sys.version_info, namedtuple.abc) And obviously: isinstance(MyNamedTuple, namedtuple.abc) # referiring to the above examples
I ment:
issubclass(namedtuple('Foo', 'x y z'), namedtuple.abc) issubclass(type(sys.version_info), namedtuple.abc) issubclass(MyNamedTuple, namedtuple.abc)
...and ipso facto:
isinstance(namedtuple('Foo', 'x y z')(1, 2, 3), namedtuple.abc) isinstance(sys.version_info, namedtuple.abc) isinstance(MyNamedTuple(1, 2, 3), namedtuple.abc)
Cheers. *j
Here is a draft implementation: http://dpaste.org/T9w6/ Please note that namedtuple API is not touched, except adding 'abc' attribute (being the abstract base class in question). Regards. *j
On Mar 27, 2011, at 8:46 AM, Jan Kaliszewski wrote:
Here is a draft implementation:
Please note that namedtuple API is not touched, except adding 'abc' attribute (being the abstract base class in question).
There is an open tracker item for a namedtuple.abc. Please attach you patch there (issue7796). Raymond
On Fri, 25 Mar 2011 15:06:37 +0100 Jan Kaliszewski <zuo@chopin.edu.pl> wrote:
...and especially:
class MyAbstractNamedTuple(namedtuple.abc): def __repr__(self): "My sophisticated __repr__()" # and e.g. some new methods...
class MyNamedTupleA(MyAbstractNamedTuple): _fields = 'a b c'
class MyNamedTupleB(MyAbstractNamedTuple): _fields = ( 'one_field', 'another_field', 'and_another_one', )
Can't you multiple inheritance instead?
class Base(tuple): ... def _method(self): return 5 ... __slots__ = () ... class C(Base, namedtuple('Point', 'x y')): ... __slots__ = () ... c = C(x=1, y=2) c C(x=1, y=2) c._method() 5 c.__dict__ Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'C' object has no attribute '__dict__' a, b = c a 1 b 2
Antoine.
Antoine Pitrou dixit (2011-03-27, 17:59):
Can't you multiple inheritance instead?
class Base(tuple): ... def _method(self): return 5 ... __slots__ = () ... class C(Base, namedtuple('Point', 'x y')): ... __slots__ = () ... c = C(x=1, y=2) c C(x=1, y=2) c._method() 5 c.__dict__ Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'C' object has no attribute '__dict__' a, b = c a 1 b 2
You're right. But my idea was to make it simple and clean from the user point of view (without all those __slots__ etc.). Another approach could be a decorator transforming a given class into namedtuple with methods defined in that class: @namedtuple.from_class class MyRecord: # or e.g. class MyRecord(MyMixinWithSomeMethods): fields = 'username password' def __str__(self): return '{0.__class__}({0.username}, ...)'.format(self) Regards. *j
On Mar 27, 2011, at 1:53 PM, Jan Kaliszewski wrote:
Another approach could be a decorator transforming a given class into namedtuple with methods defined in that class:
@namedtuple.from_class class MyRecord: # or e.g. class MyRecord(MyMixinWithSomeMethods): fields = 'username password' def __str__(self): return '{0.__class__}({0.username}, ...)'.format(self)
For the record (pun intended), I'm opposed to changing the API for namedtuples. It is a mature, successful API that stands to benefit very little from from making a second way to do it. Experimentation is great and it would be nice to have alternative recipes posted in the ASPN Cookbook or some other place, but I believe the standard library is the wrong place to fiat in a second way to create them. If a new recipe gains traction, we can link to it from the docs. Python development is currently suffering from excess enthusiasm with advanced code manipulations occurring upon instantiation -- metaclasses, decorators, and context managers are fun to play with, but no fun to debug or trace through when something goes wrong. Raymond
Is there a use case other an adding __repr__? The most popular way to use namedtuples are just are just a shorthand for defining a special type of simple class. But if you're going to be adding methods, you're breaking out of simple situation they are used for, and you might as well just free yourself and make it the class. Daniel On Sun, Mar 27, 2011 at 5:40 PM, Raymond Hettinger < raymond.hettinger@gmail.com> wrote:
On Mar 27, 2011, at 1:53 PM, Jan Kaliszewski wrote:
Another approach could be a decorator transforming a given class into namedtuple with methods defined in that class:
@namedtuple.from_class class MyRecord: # or e.g. class MyRecord(MyMixinWithSomeMethods): fields = 'username password' def __str__(self): return '{0.__class__}({0.username}, ...)'.format(self)
For the record (pun intended), I'm opposed to changing the API for namedtuples.
It is a mature, successful API that stands to benefit very little from from making a second way to do it.
Experimentation is great and it would be nice to have alternative recipes posted in the ASPN Cookbook or some other place, but I believe the standard library is the wrong place to fiat in a second way to create them. If a new recipe gains traction, we can link to it from the docs.
Python development is currently suffering from excess enthusiasm with advanced code manipulations occurring upon instantiation -- metaclasses, decorators, and context managers are fun to play with, but no fun to debug or trace through when something goes wrong.
Raymond
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
On 27.03.2011 23:40, Raymond Hettinger wrote:
Python development is currently suffering from excess enthusiasm with advanced code manipulations occurring upon instantiation -- metaclasses, decorators, and context managers are fun to play with, but no fun to debug or trace through when something goes wrong.
Not sure how context managers would fit in that category though. Georg
On Tue, Mar 29, 2011 at 3:18 AM, Georg Brandl <g.brandl@gmx.net> wrote:
On 27.03.2011 23:40, Raymond Hettinger wrote:
Python development is currently suffering from excess enthusiasm with advanced code manipulations occurring upon instantiation -- metaclasses, decorators, and context managers are fun to play with, but no fun to debug or trace through when something goes wrong.
Not sure how context managers would fit in that category though.
Badly written __exit__ methods can definitely make debugging failures interesting (although I believe 3.x exception chaining helps a lot with avoiding that). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
Here is another --shortened and possibly better-- draft implementation: http://dpaste.org/2aiQ/ Regards. *j
PS. For the record, the final recipe is here: http://code.activestate.com/recipes/577629-namedtupleabc-abstract-base-class... Bon Appétit! *j
participants (6)
-
Antoine Pitrou
-
Daniel da Silva
-
Georg Brandl
-
Jan Kaliszewski
-
Nick Coghlan
-
Raymond Hettinger