Re: [Tutor] list iteration [iteration and mutation?]

Magnus Lycka magnus at thinkware.se
Mon May 3 18:01:49 EDT 2004


Karl Pflästerer wrote:
> > I think there are three lessons we can learn from this:
> 
> > 1. Modifying a list that we are iterating over is error prone.
> > 2. Iterating backwards, from the end to the beginning, typically
> >    makes this problem go away.
> > 3. Identifying objects by *what* they are, is often more robust
> >    that to identify them based on *where* they are.
> 
> Right.  But there is a forth lesson to learn.
> 
> 4. Try a functional approach. e.g.:

Ok, but the real difference between your approach and the examples
I showed is that you avoid the entire problem by making a new list
containing the objects that I wouldn't remove.

It took me a long time to grok map, filter and reduce. Once I
did, they were obvious, but I was still reluctant to use them,
since I feared other people reading my code would be as confused
as I had once been. It seems to me that the problem is smaller
with list comprehensions, so I don't avoid that on purpose. :)

>>> l = [s for s in l if not s.startswith('m')]

is basically just a different syntax for...

>>> new_list = []
>>> for s in l:
...     if not s.startswith('m'):
...         new_list.append(s)
>>> l = new_list; del new_list

...so I think your lesson is maybe rather "avoid modifying your
list. Make a new list instead."

This usually works well, but sometimes, it isn't practical due to 
memory size reasons, if the list we manipulate is very big, but 
all my examples suffer from the same problem. :(

This memory problem with two big lists can easily be fixed by
changing my "range(len(l)-1, -1, -1)" to "xrange(len(l)-1, -1, -1)".
(The range function actually builds a list of integers, but xrange
handles this with an iterator instead.)

Also, we're not always working with a Python list as I did in my
example. The sequence we're iterating over might be a GUI listbox
or something like that. It could really look something like this:

for i in xrange(lb.count_items()-1, -1, -1):
    if lb.get_item(i).startswith('m'):
        lb.del_item(i)

> filter(lambda i: predicate(i), lst)
> 
> or
> 
> [i for i in lst if predicate(i)]
> 
> So with your example:
> 
> >>> filter(lambda s: not s.startswith('m'), l)
> ['polly', 'dolly', 'pike']
> >>> [s for s in l if not s.startswith('m')]
> ['polly', 'dolly', 'pike']

-- 
Magnus Lycka, Thinkware AB
Alvans vag 99, SE-907 50 UMEA, SWEDEN
phone: int+46 70 582 80 65, fax: int+46 70 612 80 65
http://www.thinkware.se/  mailto:magnus at thinkware.se



More information about the Tutor mailing list