3

In the code below, modification of the first type changes the original list, while in the second list stays intact. Why is the behaviour the way it is?

temp = [{"a":"b"},{"c":"d"},{"e":"f"},{"a":"c"}]

for item in temp:
    if "a" in item:
        item["a"] = "x"
print(temp)
temp = [{"a":"b"},{"c":"d"},{"e":"f"},{"a":"c"}]

for item in temp:
    item  = {}
print(temp)

Output for the first one is [{'a': 'x'}, {'c': 'd'}, {'e': 'f'}, {'a': 'x'}]

and for the second one is [{'a': 'b'}, {'c': 'd'}, {'e': 'f'}, {'a': 'c'}]

Python version is 3.6.5

Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40
Yash Gupta
  • 187
  • 2
  • 11
  • Does this answer your question? [Modify a list while iterating](https://stackoverflow.com/questions/44864393/modify-a-list-while-iterating) – accdias Dec 30 '19 at 11:54

4 Answers4

6
for item in temp:
    item  = {}

In every iteration the list element item is discarded, and instead a new local variable (that just in chance happens to be called item as well) is created and assigned with an empty dict, which in turn is discarded as well. The original list is not affected at all.

This can be visualized with id, which returns the memory address of the object:

temp = [{}]
for item in temp:
    print(id(item))
    item = {}
    print(id(item))

Outputs

2704138237016
2704138237816

Notice how we are getting 2 different ids. 1 for the dict in the list, and another for the new dict created inside the loop.


Compared to

for item in temp:
    if "a" in item:
        item["a"] = "x"

here item is never reassigned with something else (no line says item = ...), so item always points to dict in the original list. You are assigning to the 'a' key of that original item dictionary.

DeepSpace
  • 78,697
  • 11
  • 109
  • 154
2

In the first example, you're accessing the dictionaries and modifying it. In the second example, when you do item = {}, you're saying that the local variable item now points to an empty dictionary. But that doesn't modify the temp array.

The correct way to do what the second example is trying to do is:

for index in range(len(temp)):
    temp[index] = {}
Ismael Padilla
  • 5,246
  • 4
  • 23
  • 35
  • 2
    The Pythonic way to write `for index in range(len(temp)):` is `for index, _ in enumerate(temp):`. – accdias Dec 30 '19 at 11:49
2

to get a better understanding you can have a look at the similar code:

temp = [{"a":"b"},{"c":"d"},{"e":"f"},{"a":"c"}]

for index in range(len(temp)):
    item = temp[index] # linked with temp
    if 'a' in item:
        # equivalent with temp[index]['a'] = 'x'
        item['a'] = 'x'

print(temp) 

#########################################################

temp = [{"a":"b"},{"c":"d"},{"e":"f"},{"a":"c"}]

for index in range(len(temp)):
    item = temp[index] # linked with temp
    item = {} # dosen't link at all with temp / new object 

print(temp)

output:

[{'a': 'x'}, {'c': 'd'}, {'e': 'f'}, {'a': 'x'}]
[{'a': 'b'}, {'c': 'd'}, {'e': 'f'}, {'a': 'c'}]
kederrac
  • 16,819
  • 6
  • 32
  • 55
1

Behaviour of second example is appropriately documented in Python built-in help. Just:

>>> help('for')

Excerpt from help:

The for-loop makes assignments to the variables in the target list. This overwrites all previous assignments to those variables including those made in the suite of the for-loop:

for i in range(10):
       print(i)
       i = 5             # this will not affect the for-loop
                         # because i will be overwritten with the next
                         # index in the range
Aivar Paalberg
  • 4,645
  • 4
  • 16
  • 17