For-each behavior while modifying a collection

Wolfgang Maier wolfgang.maier at biologie.uni-freiburg.de
Thu Nov 28 18:21:57 CET 2013


Valentin Zahnd <v.zahnd <at> gmail.com> writes:

> 
> Hello
> 
> For-each does not iterate ober all entries of collection, if one
> removes elements during the iteration.
> 
> Example code:
> 
> def keepByValue(self, key=None, value=[]):
>     for row in self.flows:
>         if not row[key] in value:
>             self.flows.remove(row)
> 
> It is clear why it behaves on that way. Every time one removes an
> element, the length of the colleciton decreases by one while the
> counter of the for each statement is not.
> The questions are:
> 1. Why does the interprete not uses a copy of the collection to
> iterate over it? Are there performance reasons?
> 2. Why is the counter for the iteration not modified?
> 
> Valentin
> 

I guess because it's difficult to generalize this idea.
Python for loops use the iterator protocol, i.e., in order to be usable in a
for loop all an object has to provide is an __iter__ and a __next__ method,
but your suggestion #1 would require it to define a copy method in addition.
As for #2: there is no such thing as a loop counter in a standard for loop,
but it's the iterated object that decides on the next value the loop will
see, and there's no way to move back, e.g.:
class jumplist (list):
    def __iter__(self):
        n=0
        while True:
            if n%3:
                yield self[n]
            else:
                yield None
            n+=1
            if n>=len(self):
                break

jumper=jumplist(range(10))

for element in jumper:
    print(element)

---->
None
1
2
None
4
5
None
7
8
None

Best,
Wolfgang




More information about the Python-list mailing list