On 28/11/2013 17:20, Ned Batchelder wrote:
On 11/28/13 10:49 AM, Valentin Zahnd wrote:
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?

Because implicit copying would be pointless in most cases.  Most loops
don't even want to modify the collection, why copy all iterables just in
case your loop might be one of the tiny few that might change the
collection?

Of course, if that prices is acceptable to you, you could do the copy
yourself:

      for row in list(self.flows):
          if row[key] not in value:
              self.flows.remove(row)

2. Why is the counter for the iteration not modified?

Because the list and the iterator over the list are different objects.
I suppose the list and the iterator could have been written to update
when the list is modified, but it could get pretty complicated, even
more so if you want to do the same for other collections like dictionaries.

The best advice is: don't modify the list, instead make a new list:

      self.flows = [r for r in self.flows if r[key] not in value]

Be careful though, since there might be other references to the list,
and now you have two.

The simple solution in that case is:

    self.flows[:] = [r for r in self.flows if r[key] not in value]

--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to