[Tutor] working with new classes

C Smith smichr at hotmail.com
Thu Mar 10 00:17:59 CET 2005


Thanks to Sean and Kent for replies.  I found a site that provided some  
good examples, too, at  
http://www.cafepy.com/articles/python_attributes_and_methods/ 
ch03s02.html

Here's a blurb from the title page:

---- wep page excerpt

Shalabh Chaturvedi
Copyright © 2004 Shalabh Chaturvedi

This book is part of a series:

Python Types and Objects

Python Attributes and Methods [you are here]
----

After playing with this for a while I get the feeling that trying to  
create an alternate access for the list is not the way to go.  I was  
able to define the following methods with success...

###
class Ring(list):
	def __init__(self,l):
		list.__init__(self,l)
		self._zero=0

	def turn(self,incr=1):
		self._zero+=incr

	def __getitem__(self,i):
		if type(i)==int:
			return list.__getitem__(self,(i-self._zero)%len(self))
		else:
			return [list.__getitem__(self,(k-self._zero)%len(self)) for k in  
range(i.start,i.stop,i.step)]
			
	def __setitem__(self,i,v):
		list.__setitem__(self,(i-self._zero)%len(self),v)
	
	def __getslice__(self,i,j):
		return  
list.__getslice__(self,(i-self._zero)%len(self),(j- 
self._zero)%len(self))

	def __setslice__(self,i,j,v):
		list.__setslice__(self,(i-self._zero)%len(self),(j- 
self._zero)%len(self),v)

	def __repr__(self):
		return repr([self[i] for i in range(len(self))])
###
..but then something like pop(3) pops the original element not the  
element in the 3rd position of the turned list:

###
 >>> l=Ring(range(10))
 >>> l.turn(5)
 >>> print l
[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
 >>> l.pop(3); print l
[5, 6, 7, 8, 9, 0, 1, 2, 4] #I wanted the 8 to go
###

So in the absence of being able to redefine in the class the way that  
indices should be computed (like the way that your own cmp function can  
be supplied for the sort method) it seems best to use the existing  
structure and either access the list by passing it indices which have  
been remapped:

###
 >>> def ring_index(i):
	return (i-ring_zero)%ring_length

 >>> l = range(10)
 >>> ring_length = len(l)
 >>> ring_zero = 3 #does a virtual shift to the right 3 elements
 >>> print l[ring_index(0)]
7
###

But this will only help you look at individual entries and slices that  
don't go across the boundaries of the list.

Alternatively, the list class can be appended with helpers like 'turn'  
and 'segment' which can actually turn the "ring" and remove a piece  
from it without worrying about the endpoint:

###
 >>> class ring(list):
	def turn(self, incr=1):
		incr%=len(self)
		self[:] = self[incr:]+self[:incr]
	def segment(self, i, length, incr=1):
		length=min(len(self),length)
		if i+length>len(self):
			return self[i::incr]+self[(length-i)%incr:i+length-len(self):incr]

 >>> l=ring(range(20)); l.turn(3); print l
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2]
 >>> >>> l.segment(17,5,3) #start at 17, length of 5, stride 3
[0, 3]
###

This is my first intoduction to the new class modifications...initially  
it seems nice to be able to wrap your methods up into a class like this  
rather than creating dangling functions in one's program.

/c




More information about the Tutor mailing list