Re: [Tutor] subclassing list -- slicing doesn't preserve type
> > > I'm trying to figure out how to subclass the list built-in. > > > You could do it e.g. like that: > > > > class Mylist (list): > > def __init__(self, seq=None): > > super(self.__class__, self).__init__(seq) > > def __getslice__(self, start, stop): > > return self.__class__(super(self.__class__, > > self).__getslice__(start, stop)) > > def __getitem__(self, key): > > if isinstance(key, slice): > > return self.__class__(super(self.__class__, > > self).__getitem__(key)) > > else: > > return super(self.__class__, self).__getitem__(key) We might want to bring up that using inheritance here might be an inappropriate OOP construct here. It might be better to handle this sort of thing by wrapping a list in a wrapper, and work through delegation. In fact, that's essentially what UserList is. I'm not sure I agree with the documentation of: http://www.python.org/doc/lib/module-UserList.html where it says that subclassing 'list' is usually appropriate. It seems awfully messy to have to overload every method that can potentially produce a new list. And besides, all that work is being done in UserList already: ### >>> from UserList import UserList >>> class MyList(UserList): ... pass ... >>> l = MyList() >>> l.append('a') >>> l.append('b') >>> l.append('c') >>> l2 = l[1:] >>> isinstance(l2, MyList) True ### ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] subclassing list -- slicing doesn't preserve type
Karl Pflästerer said unto the world upon 2005-02-22 07:53: On 22 Feb 2005, [EMAIL PROTECTED] wrote: I'm trying to figure out how to subclass the list built-in. .>>> class my_list(list): def __init__(self, sequence=None): list.__init__(self, sequence) self.spam = 1 So, how can I get slicing to preserve the my_list type? And why does the above class get so much for free, but not slicing? It gets also slicing for free but think about what happens when you call e.g. `append'; you *mutate an existing object in place* (i.e. a destructive operation). So you change the already existing object which is an instance of Mylist. On the other hand with slicing you get a *new* object back; you never told Python that you also wanted that new object to be of type Mylist. You could do it e.g. like that: class Mylist (list): def __init__(self, seq=None): super(self.__class__, self).__init__(seq) def __getslice__(self, start, stop): return self.__class__(super(self.__class__, self).__getslice__(start, stop)) def __getitem__(self, key): if isinstance(key, slice): return self.__class__(super(self.__class__, self).__getitem__(key)) else: return super(self.__class__, self).__getitem__(key) For simple slices Python calls `list.__getslice__' for extended slices list.__getitem__ gets called. So the above handles all cases. You must also think about the other methods which return a newly allocated object. Karl Thanks Karl (and Kent in another response), use of super is new to me; from a quick glance at the docs, I am glad to have been pointed at it. For the quick and dirty, I think I will go the __getslice__ way, deprecation be damned. But, learning how to do it the way you have above is high on the list of things to do. Thanks and best, Brian vdB ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] subclassing list -- slicing doesn't preserve type
Brian van den Broek wrote: Hi all, I'm trying to figure out how to subclass the list built-in. .>>> class my_list(list): def __init__(self, sequence=None): list.__init__(self, sequence) self.spam = 1 .>>> mine = my_list((1,2,3,4)) .>>> mine.append(42) .>>> mine [1, 2, 3, 4, 42] .>>> type(mine) .>>> damn = mine[1:3] .>>> type(damn) .>>> damn [2, 3] .>>> I had thought that by subsclassing list I got all list-like properties for free. Append (among others) are available for my_list instances. But slicing returns a list, rather than a my_list. I can see that this is list-like in it's way, but I'd rather have be so in mine ;-) The problem is that the list methods that return a new list don't know to return an object of your class. You will have to override those methods with a new method that converts the new list to an instance of my_list. Or you can use UserList which does this for you: class my_list(list): def __init__(self, sequence=None): list.__init__(self, sequence) self.spam = 1 def __getslice__(self, i, j): return my_list(list.__getslice__(self, i, j)) print 'Subclass list:' mine = my_list((1,2,3,4)) mine.append(42) print 'mine:', mine print 'type(mine):', type(mine) print damn = mine[1:3] print 'damn', damn print 'type(damn):', type(damn) print from UserList import UserList class my_list2(UserList): def __init__(self, sequence=None): UserList.__init__(self, sequence) self.spam = 1 print 'Subclass UserList:' mine = my_list2((1,2,3,4)) mine.append(42) print 'mine:', mine print 'mine.__class__:', mine.__class__ print damn = mine[1:3] print 'damn', damn print 'damn.__class__:', damn.__class__ prints: Subclass list: mine: [1, 2, 3, 4, 42] type(mine): damn [2, 3] type(damn): Subclass UserList: mine: [1, 2, 3, 4, 42] mine.__class__: __main__.my_list2 damn [2, 3] damn.__class__: __main__.my_list2 If you decide to stick with subclassing list, UserList can still be your guide for which methods need wrappers. Look for the calls to self.__class__() in UserList.py. I've read in the docs that UserList is discouraged, and in the Nutshell that the __getslice__, etc. special methods are depreciated. So, how can I get slicing to preserve the my_list type? And why does the above class get so much for free, but not slicing? Best, and thanks to all, Brian vdB ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] subclassing list -- slicing doesn't preserve type
On 22 Feb 2005, [EMAIL PROTECTED] wrote: > I'm trying to figure out how to subclass the list built-in. > > .>>> class my_list(list): > def __init__(self, sequence=None): > list.__init__(self, sequence) > self.spam = 1 > > .>>> mine = my_list((1,2,3,4)) > .>>> mine.append(42) > .>>> mine > [1, 2, 3, 4, 42] > .>>> type(mine) > > .>>> damn = mine[1:3] > .>>> type(damn) > > .>>> damn > [2, 3] > .>>> > > I had thought that by subsclassing list I got all list-like properties > for free. Append (among others) are available for my_list instances. > But slicing returns a list, rather than a my_list. I can see that this > is list-like in it's way, but I'd rather have be so in mine ;-) > > I've read in the docs that UserList is discouraged, and in the > Nutshell that the __getslice__, etc. special methods are depreciated. But the problem is here: list() defines a __getslice__ method. > So, how can I get slicing to preserve the my_list type? And why does > the above class get so much for free, but not slicing? It gets also slicing for free but think about what happens when you call e.g. `append'; you *mutate an existing object in place* (i.e. a destructive operation). So you change the already existing object which is an instance of Mylist. On the other hand with slicing you get a *new* object back; you never told Python that you also wanted that new object to be of type Mylist. You could do it e.g. like that: class Mylist (list): def __init__(self, seq=None): super(self.__class__, self).__init__(seq) def __getslice__(self, start, stop): return self.__class__(super(self.__class__, self).__getslice__(start, stop)) def __getitem__(self, key): if isinstance(key, slice): return self.__class__(super(self.__class__, self).__getitem__(key)) else: return super(self.__class__, self).__getitem__(key) For simple slices Python calls `list.__getslice__' for extended slices list.__getitem__ gets called. So the above handles all cases. . >>> L = Mylist((1,2,3,4)) . >>> L[1] . 2 . >>> L[1:2] . [2] . >>> type(_) . . >>> L[0:4:2] . [1, 3] . >>> type(_) . . >>> You must also think about the other methods which return a newly allocated object. Karl -- Please do *not* send copies of replies to me. I read the list ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor