Why changing of set in body of for does not affect on for range in python?

Viewed 28

I want to affect on for range from for body by changing the set.

s1 = {1,2,3}
s2 = {4,5,6}

for p in s1:
  print(p)
  if p == 2:
    s1 = s1.union(s2)

I expect to get

1
2
3
4
5
6

but I got:

1
2
3
1 Answers

You cannot change the set size during an iteration if you're looping over the set.

This works (although it's spectacularly bad code) because it uses a list:

s = [1, 2]

for i in s:
    if i < 3:
        s.append(i+2)
    print(i)

Output:

1
2
3
4

However, this does not:

s = {1, 2}

for i in s:
    if i < 3:
        l.add(i+2)
    print(i)

Result:

    for i in l:
RuntimeError: Set changed size during iteration

It throws that error because the actual set s was modified in-place.

However, when you do what you're doing, you're creating a new set and assiging it to the original variable, but it's a new set and thus not the set the loop is still iterating over, which will continue to exist (now unnamed) until the loop completes:

s = {1, 2}

for i in s:
    if i < 3:
        # a new set, not affecting the set you're looping over
        s = s.union({i+2})
    print(i)

Output:

1
2

Your loop isn't looping over s, it's looping over the set that s was assigned at the start of the loop and you changed what s was assigned during the loop - but that doesn't affect the loop.

This explains why you don't get the runtime error, but you also don't get the result you expected. At the end of the loop, s will be {1, 2, 3, 4} though (regardless of the value i is being compared to, as long as it's larger than 2, since the loop will iterate twice - the length of s at the start).

Related