Re: [Tutor] subclassing list -- slicing doesn't preserve type

2005-02-22 Thread Danny Yoo

> > > 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

2005-02-22 Thread Brian van den Broek
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

2005-02-22 Thread Kent Johnson
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

2005-02-22 Thread Karl =?iso-8859-1?Q?Pfl=E4sterer?=
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