Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Variable assignment in a for loop

I understand that in Python regular c++ style variable assignment is replaced by references to stuff ie

a=[1,2,3]
b=a
a.append(4)
print(b)       #gives [1,2,3,4]
print(a)       #gives [1,2,3,4]

but I'm still confused why an analogous situation with basic types eg. integers works differently?

a=1
b=a
a+=1
print(b)          # gives 1
print(a)          # gives 2

But wait, it gets even more confusing when we consider loops!

li=[1,2,3]
for x in li:
    x+=1
print(li)     #gives [1,2,3]

Which is what I expected, but what happens if we do:

a,b,c=1,2,3
li=[a,b,c]
for x in li:
    x+=1
print(li)        #gives [1,2,3]

Maybe my question should be how to loop over a list of integers and change them without map() as i need a if statement in there. The only thing I can come up short of using

for x in range(len(li)):
    Do stuff to li[x]

is packaging the integers in one element list. But there must be a better way.

like image 437
Michal Avatar asked Dec 02 '22 20:12

Michal


2 Answers

Well, you need to think of mutable and immutable type.

For a list, it's mutable. For a integer, it's immutable, which means you will refer to a new object if you change it. When a+=1 is executed, a will be assigned a new object, but b is still refer to the same one.

like image 53
chinuy Avatar answered Dec 05 '22 10:12

chinuy


a=[1,2,3]
b=a
a.append(4)
print(b)       #[1,2,3,4]
print(a)       #[1,2,3,4]

Here you are modifying the list. The list content changes, but the list identity remains.

a=1
b=a
a+=1

This, however, is a reassignment. You assign a different object to a.

Note that if you did a += [4] in the 1st example, you would have seen the same result. This comes from the fact that a += something is the same as a = a.__iadd__(something), with a fallback to a = a.__add__(something) if __iadd__() doesn't exist.

The difference is that __iadd__() tries to do its job "inplace", by modifying the object it works on and returning it. So a refers to the same as before. This only works with mutable objects such as lists.

On immutable objects such as ints __add__() is called. It returns a different object, which leads to a pointing to another object than before. There is no other choice, as ints are immutable.


a,b,c=1,2,3
li=[a,b,c]
for x in li:
    x+=1
print(li)        #[1,2,3]

Here x += 1 means the same as x = x + 1. It changes where x refers to, but not the list contents.

Maybe my question should be how to loop over a list of integers and change them without >map() as i need a if statement in there.

for i, x in enumerate(li):
    li[i] = x + 1

assigns to every list position the old value + 1.

like image 44
glglgl Avatar answered Dec 05 '22 11:12

glglgl