[Tutor] Tutor Digest, Vol 30, Issue 68

Carroll, Barry Barry.Carroll at psc.com
Tue Aug 22 02:49:43 CEST 2006


Hello, Marcus

> Date: Mon, 21 Aug 2006 16:50:37 -0400
> From: "Marcus Goldfish" <magoldfish at gmail.com>
> Subject: [Tutor] custom container subclassing list-- slices are
> 	lists!?
> To: Tutor <tutor at python.org>
> Message-ID:
> 	<5e183f3d0608211350w73241fa6n967e9c742ce8b5eb at mail.gmail.com>
> Content-Type: text/plain; charset="iso-8859-1"
> 
> Hi,
> 
> I'd like to sublcass the built-in list type to create my own
container.
> How
> can I make slices of the list be of type myclass-- currently they are
> lists.  Example:
> 
> >>> class MyFoo(list):
>            def __init__(self, inlist):
>                   self = inlist[:]
> >>> me = MyFoo(range(10))

I'll start with a side question: did you check the contents of me?  When
I did this (using the IPython shell running on Python 2.3) I got the
following:

**********
@BCARROLL[Python]|1> class MyFoo(list):
                 |.>     def __init__(self, inlist):
                 |.>         self = inlist[:]
                 |.>
@BCARROLL[Python]|2> me = MyFoo(range(10))
@BCARROLL[Python]|3> me
                 <3> []
**********

The identifier me did not get the list you wanted
([0,1,2,3,4,5,6,7,8,9]).  I don't know why.  Perhaps one of the more
experienced people on the list knows.

> >>> type(me)
> <class '__main__.MyFoo'>

This worked okay: the empty list is of type class MyFoo

> 
> >>> type(me[0:3])
> <type 'list'>

So far, you have only defined one special method for your class:
__init__.  All the other operations available for instances of your
class come from the base class list.  And the slicing operator for the
list class returns ... you guessed it ... a list.  In order to return an
instance or your class, you must override the slicing operator in your
class definition.  

Doing this correctly is not simple.  The slicing operator is implemented
by three special methods (__getitem__, __setitem__ and __delitem__),
each of which takes a slice OBJECT as a parameter.  Overriding these
three methods is pretty advanced Python.  "Python in a Nutshell, 2nd
Edition" (my Python bible) says, 

	"... It's best to avoid this complication by simply not defining

	the slice-specific special methods in your classes; however, 
	you may need to override these methods if your class subclasses 
	list or tuple and you want to provide special functionality when

	an instance of your class is sliced with just one colon. ..."
	[Section 5.2.2.4, Container Slicing]

So, the question to ask yourself is, "Do I require special functionality
when slicing a MyFoo object?".  If not, then don't worry that the
slice's type is different than that of the original instance.

If the answer is yes, however, you can try subclassing UserList.  Module
UserList was written back when built-in types like list could not be
subclassed.  It uses the now deprecated special methods __getslice__,
__setslice__ and __delslice__, and it is no longer entirely complete or
correct.  But it still works pretty well.  And, it also overrides many
other operators that apply to lists.  (Read about it in "Python Library
Reference" Section 3.8 and UserList.py.)

Using this module, your code would look like this:

**********
@BCARROLL[Python]|1> from UserList import UserList
@BCARROLL[Python]|2> class MyFoo(UserList):
                 |.>     def __init__(self, inlist):
                 |.>         UserList.__init__(self, inlist)
                 |.>
@BCARROLL[Python]|3> me = MyFoo(range(10))
@BCARROLL[Python]|4> me
                 <4> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
**********

Note that this construction handles the range method correctly.

**********
@BCARROLL[Python]|5> type(me)
                 <5> <type 'instance'>
@BCARROLL[Python]|6> isinstance(me, MyFoo)
                 <6> True
**********

Note here that the type method doesn't show me to be an instance of
MyFoo, but that isinstance does.  

**********
@BCARROLL[Python]|7> me[0:3]
                 <7> [0, 1, 2]
@BCARROLL[Python]|8> type(me[0:3])
                 <8> <type 'instance'>
@BCARROLL[Python]|9> isinstance(me[0:3], MyFoo)
                 <9> True 
**********

And finally, the slice is in fact an instance of MyFoo.

> All help appreciated!

Sorry for being so long-winded.  I hope this helps.  
> 
> Thanks,
> Marcus

Regards,
 
Barry
barry.carroll at psc.com
541-302-1107
________________________
We who cut mere stones must always be envisioning cathedrals.

-Quarry worker's creed





More information about the Tutor mailing list