Modifying a list iterator in Python not allowed?

Deadly 提交于 2019-12-17 20:57:21

问题


Simple example:

myList = [1, 2, 3, 4, 5]
for obj in myList:
  obj += 1
print myList

prints

[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

while:

myList = [1, 2, 3, 4, 5]
for index in range(0,len(myList)):
  myList[index] += 1
print myList

prints

[1, 2, 3, 4, 5]
[2, 3, 4, 5, 6]

Conclusion:

  1. Lists can be modified in place using global list access Lists can
  2. List items can NOT be modified in place using the iterator object

All example code I can find uses the global list accessors to modify the list inplace. Is it so evil to modify a list iterator?


回答1:


in for obj in myList:, in every iteration, obj is a (shallow) copy of the element in myList. So the change on the obj does nothing to myList's elements.

It's different with the Perl for my $obj (@myList) {}




回答2:


The reason obj += 1 does not do what you expect is that this statement does not modify obj in-place. Instead, it computes the new value, and rebinds the variable obj to point to the new value. This means that the contents of the list remain unchanged.

In general it is possible to modify the list while iterating over it using for obj in myList. For example:

myList = [[1], [2], [3], [4], [5]]
for obj in myList:
  obj[0] += 1
print(myList)

This prints out:

[[2], [3], [4], [5], [6]]

The difference between this and your first example is that here, the list contains mutable objects, and the code modifies those objects in-place.

Note that one could also write the loop using a list comprehension:

myList = [val+1 for val in myList]



回答3:


I think you've misunderstood what an "iterator object" is. A for loop is not an iterator object. For all intents and purposes, a for loop like this:

myList = [0, 1, 2, 3, 4]
for x in myList:
    print x

does this (but more efficiently and less verbosely):

i = 0
while i < len(myList)
    x = myList[i]
    print x
    i += 1

So you see, any changes made to x are lost as soon as the next loop starts, because the value of x is overwritten by the value of the next item in the list.

As others have observed, it is possible to alter the value of a list while iterating over it. (But don't change its length! That's where you get into trouble.) One elegant way to do so is as follows:

for i, x in enumerate(myList):
    myList[i] = some_func(x)

Update: It's also important to understand that no copying goes on in a for loop. In the above example, i and x -- like all variables in Python -- are more like pointers in C/C++. As the for loop progresses, obj points at myList[0], myList[1], etc, in turn. And like a C/C++ pointer, the properties of the object pointed to are not changed when the pointer is changed. But also like a C pointer, you can directly modify the thing pointed at, because it's not a copy. In C, this is done by dereferencing the pointer; in Python, this is done by using a mutable object. That's why NPE's answer works. If i and x were even shallow copies, it wouldn't be possible to do what he does.

The reason you can't directly change ints the way you can change lists (as in NPE's answer), is that ints aren't mutable. Once a 5 object is created, nothing can change its value. That's why passing around a pointer to 5 is safe in Python -- no side-effects can occur, because the thing pointed to is immutable.




回答4:


You are confused. Consider your first snippet:

myList = [1, 2, 3, 4, 5]
for obj in myList:
  obj += 1
print a

obj is not some kind of magical pointer into the list. It is a variable which holds a reference to an object which happens to also be in myList. obj += 1 has the effect of increasing the value stored in obj. Your code then does nothing with that value.

To be clear: There are no copies in this code example. obj is a variable, which holds an object in the list. That is all.




回答5:


In the first example the integer is copied into obj which is increased by 1. The list is not changed.

If you would use a class instance and perform operations on it, it would be changed.




回答6:


Modification in list is allowed. Your code examples arbove are pretty garbled...

myList = [1, 2, 3, 4, 5]
for index in range(0,len(myList)):
   myList[index] += 1
 print myList

This works.



来源:https://stackoverflow.com/questions/9414399/modifying-a-list-iterator-in-python-not-allowed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!