Modify a list while iterating

2019-01-28 13:05发布

I know you should not add/remove items while iterating over a list. But can I modify an item in a list I'm iterating over if I do not change the list length?

class Car(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return type(self).__name__ + "_" + self.name

my_cars = [Car("Ferrari"), Car("Mercedes"), Car("BMW")]
print(my_cars)  # [Car_Ferrari, Car_Mercedes, Car_BMW]
for car in my_cars:
    car.name = "Moskvich"
print(my_cars)  # [Car_Moskvich, Car_Moskvich, Car_Moskvich]

Or should I iterate over the list indices instead? Like that:

for car_id in range(len(my_cars)):
    my_cars[car_id].name = "Moskvich"

The question is: are the both ways above allowed or only the second one is error-free?

If the answer is yes, will the following snippet be valid?

lovely_numbers = [[41, 32, 17], [26, 55]]
for numbers_pair in lovely_numbers:
    numbers_pair.pop()
print(lovely_numbers)  # [[41, 32], [26]]

UPD. I'd like to see the python documentation where it says "these operations are allowed" rather than someone's assumptions.

4条回答
戒情不戒烟
2楼-- · 2019-01-28 13:20

I know you should not add/remove items while iterating over a list. But can I modify an item in a list I'm iterating over if I do not change the list length?

Your not modifying the list in any way at all. What you are modifying is the elements in the list; That is perfectly fine. As long as you don't directly change the actual list, you're fine.

There's no need to iterate over the indices. In fact, that's unidomatic. Unless you are actually trying to change the list itself, simply iterate over the list by value.

If the answer is yes, will the following snippet be valid?

lovely_numbers = [[41, 32, 17], [26, 55]]
for numbers_pair in lovely_numbers:
    numbers_pair.pop()
print(lovely_numbers)  # [[41, 32], [26]]

Absolutely. For the exact same reasons as I said above. Your not modifying lovely_numbers itself. Rather, you're only modifying the elements in lovely_numbers.

查看更多
欢心
3楼-- · 2019-01-28 13:28

You are not modifying the list, so to speak. You are simply modifying the elements in the list. I don't believe this is a problem.

To answer your second question, both ways are indeed allowed (as you know, since you ran the code), but it would depend on the situation. Are the contents mutable or immutable?

For example, if you want to add one to every element in a list of integers, this would not work:

>>> x = [1, 2, 3, 4, 5]
>>> for i in x:
...     i += 1
... 
>>> x
[1, 2, 3, 4, 5] 

Indeed, ints are immutable objects. Instead, you'd need to iterate over the indices and change the element at each index, like this:

>>> for i in range(len(x)):
...     x[i] += 1
...
>>> x
[2, 3, 4, 5, 6]

If your items are mutable, then the first method (of directly iterating over the elements rather than the indices) is more efficient without a doubt, because the extra step of indexing is an overhead that can be avoided since those elements are mutable.

查看更多
够拽才男人
4楼-- · 2019-01-28 13:31

Of course, you can. The first way is normal, but in some cases you can also use list comprehensions or map().

查看更多
【Aperson】
5楼-- · 2019-01-28 13:33

Examples where the list is modified and not during while iterating over the elements of the list

list_modified_during_iteration.py

a = [1,2]
i = 0
for item in a:
      if i<5:
          print 'append'
          a.append(i+2)
      print a
      i += 1

list_not_modified_during_iteration.py (Changed item to i)

a = [1,2]
i = 0
for i in range(len(a)):
    if i<5:
        print 'append'
        a.append(i+2)
    print a
    i += 1
查看更多
登录 后发表回答