From: Frank Millman on 31 Mar 2010 02:49 Hi all I needed something similar to, but not quite the same as, collections.namedtuple. The differences are that namedtuple requires the 'names' to be provided at creation time, and then lends itself to creating multiple instances of itself. I wanted a more generic class where I could supply the 'names' and 'values' at instantiation time. I came up with a simple solution that seems to work - >>> class MyTuple(tuple): .... def __new__(cls, names, values): .... for name, value in zip(names, values): .... setattr(cls, name, value) .... return tuple.__new__(cls, values) .... >>> names = ['A', 'B', 'C'] >>> values = ['a', 'b', 'c'] >>> >>> tup = MyTuple(names, values) >>> >>> print tup ('a', 'b', 'c') >>> >>> print tup[0] a >>> >>> print tup.B b >>> Then I had a need to add elements after the tuple had been created. As tuples are immutable, I thought it would be easy to change it to a list. However, it does not work - >>> class MyList(list): .... def __new__(cls, names, values): .... for name, value in zip(names, values): .... setattr(cls, name, value) .... return list.__new__(cls, values) .... >>> names = ['A', 'B', 'C'] >>> values = ['a', 'b', 'c'] >>> >>> lst = MyList(names, values) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: list() takes at most 1 argument (2 given) >>> I can find a workaround, but I would be interested to know the reason why it does not work. Version is 2.6.2. Thanks Frank Millman
From: lbolla on 31 Mar 2010 04:18 On Mar 31, 7:49 am, "Frank Millman" <fr...(a)chagford.com> wrote: > Hi all > > I needed something similar to, but not quite the same as, > collections.namedtuple. > > The differences are that namedtuple requires the 'names' to be provided at > creation time, and then lends itself to creating multiple instances of > itself. I wanted a more generic class where I could supply the 'names' and > 'values' at instantiation time. > > I came up with a simple solution that seems to work - > > >>> class MyTuple(tuple): > > ... def __new__(cls, names, values): > ... for name, value in zip(names, values): > ... setattr(cls, name, value) > ... return tuple.__new__(cls, values) > ... > > >>> names = ['A', 'B', 'C'] > >>> values = ['a', 'b', 'c'] > > >>> tup = MyTuple(names, values) > > >>> print tup > ('a', 'b', 'c') > > >>> print tup[0] > a > > >>> print tup.B > b > > Then I had a need to add elements after the tuple had been created. As > tuples are immutable, I thought it would be easy to change it to a list. > However, it does not work - > > >>> class MyList(list): > > ... def __new__(cls, names, values): > ... for name, value in zip(names, values): > ... setattr(cls, name, value) > ... return list.__new__(cls, values) > ...>>> names = ['A', 'B', 'C'] > >>> values = ['a', 'b', 'c'] > > >>> lst = MyList(names, values) > > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > TypeError: list() takes at most 1 argument (2 given) > > > > I can find a workaround, but I would be interested to know the reason why it > does not work. > > Version is 2.6.2. > > Thanks > > Frank Millman When subclassing immutable types, you need to override __new__; otherwise you need to override __init__. Here is an in-depth explanation: http://www.python.org/download/releases/2.2/descrintro/#metaclasses Here is some code: class MyTuple(tuple): def __new__(cls, names, values): for name, value in zip(names, values): setattr(cls, name, value) return tuple.__new__(cls, values) class MyList(list): def __init__(self, names, values): list.__init__(self, values) for name, value in zip(names, values): setattr(self, name, value) names = ['A', 'B', 'C'] values = ['a', 'b', 'c'] tup = MyTuple(names, values) print tup print tup[0] print tup.B lst = MyList(names, values) print lst print lst[0] print lst.B L.
From: Frank Millman on 31 Mar 2010 04:29 "lbolla" <lbolla(a)gmail.com> wrote in message news:f8011c0b-0b1b-4a4f-94ff-304c16ef9a5b(a)q16g2000yqq.googlegroups.com... On Mar 31, 7:49 am, "Frank Millman" <fr...(a)chagford.com> wrote: >> Hi all >> > When subclassing immutable types, you need to override __new__; > otherwise you need to override __init__. Perfect. Thanks very much. Frank
From: Bruno Desthuilliers on 31 Mar 2010 04:58 lbolla a �crit : > > class MyList(list): > def __init__(self, names, values): > list.__init__(self, values) > for name, value in zip(names, values): > setattr(self, name, value) > > names = ['A', 'B', 'C'] > values = ['a', 'b', 'c'] > > lst = MyList(names, values) > print lst > print lst[0] > print lst.B > >>> lst[0] = "foobar" >>> lst.A 'a'>>> lst.B = 42 >>> lst[1] 'b' >>> lst.D="duh" >>> lst[3] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
From: Rob Williscroft on 31 Mar 2010 05:02
Frank Millman wrote in news:mailman.1360.1270018159.23598.python- list(a)python.org in comp.lang.python: > I came up with a simple solution that seems to work - > >>>> class MyTuple(tuple): > ... def __new__(cls, names, values): > ... for name, value in zip(names, values): > ... setattr(cls, name, value) > ... return tuple.__new__(cls, values) > ... >>>> names = ['A', 'B', 'C'] >>>> values = ['a', 'b', 'c'] >>>> >>>> tup = MyTuple(names, values) >>>> Are you aware you are adding attributes to the class here, IOW: MyTuple.C == 'c' If you want to add attibutes to the instance: class MyTuple(tuple): def __new__(cls, names, values): r = tuple.__new__(cls, values) for name, value in zip(names, values): setattr(r, name, value) return r names = ['A', 'B', 'C'] values = ['a', 'b', 'c'] tup = MyTuple(names, values) assert tup[0] == 'a' assert tup.B == 'b' try: MyTuple.C except AttributeError: pass else: assert False |