mutable list iterators - a proposal

Raymond Hettinger python at rcn.com
Sun Mar 21 15:10:32 EST 2004


> > Also, I'm not sure your proposal is self-consistent.  If I read it
> > correctly, there is a strong notion of having the iterator remember
> > the last item emitted even if its position changes.  However, with a
> > combination of slice deletion and insertion, the notion of the last
> > item emitted becomes muddy:
> > 
> > lyst = range(10)
> > it = iter(lyst)
> > for i in xrange(5):
> >    it.next()
> > lyst[3:7] = [20]
> > print it.next()          # Should this print 20 or 7 ?
> 
> In this case my class returns a 20.  My thinking on this was that if a
> slice containing the "normal" next item is replaced by a slice,

When designing a new type, the trick is to avoid areas where two
different people could reasonably expect different "normal" behaviors.
 Otherwise, you're doing more harm than good and making it likely that
your users will stumble into a class of bugs that are extremely
difficult to hunt down.

They are truly much better off with the paradigm of looping through
one list and building another.  In-place alteration is as icebergs are
to the Titanic.  Only the simplest cases are reasonable (changing
values but not size; or reverse iterating and popping away items after
the current position).

 > > Py2.4 adds a new type, collections.deque(), that can reasonably
be
> > made to do what your asking (workable because there is no slicing,
> > just appending or popping from either end and setitem value
> > mutations):
 . . .
> This looks great.  It would indeed work for the class I had in mind. 
> Frankly, the fact that the iterator for deque works *correctly* seems
> to beg the question, "why doesn't the iterator for list work
> correctly?"  

What makes lists different is that slicing operations can alter them
in the middle.  The inconsistencies disappear at the end points. 
Deques only mutate at the ends, so you always have a clear definition
of "what's next".



>  There follows a revision of the
> code I posted originally, which attempts to demonstrate that.

The code is an improvement, but still suffers from the definitional
ambiguity mentioned above.  I believe this is inescapable.  Consider a
line at movie, you leave the line, others join in the middle, others
leave, a few more join, a few more leave, now who is the person who
"naturally" comes after you.

All the contortions in the code still suggest to me that the use case
needs a different algorithm.  Try rewriting it with separate input and
output lists.  My bet is that the code is clearer and more
maintainable.


 
> import itertools

Hey, hey, I love to see people using my module ;-)


> class muterable_list(list):
>     """just like a list except it iterates gracefully under
> mutation"""

There is one word in the docstring that is debatable.  Any guesses ;-)



Raymond Hettinger



More information about the Python-list mailing list