chamathabeysinghe
chamathabeysinghe

Reputation: 868

Why python arguments change sometimes?

This is the code I type. Here the value of int has not changed outside of function but value of list has changed.I was expecting the value of list will not change. What is the reason?

>>> def p1(list1):
    list1[0]=1000

>>> def p2(i):
    i+=10

>>> li=[1,2,3,4,5]
>>> int1=10
>>> p1(li)
>>> p2(int1)
>>> li
[1000, 2, 3, 4, 5]
>>> int1
10

Upvotes: 0

Views: 62

Answers (3)

chepner
chepner

Reputation: 530940

Note that in p1, you are not assigning a value to list1, which is the name of a variable local to p1. You are actually assigning to the first element of the list object referenced by list1, which is the same list object referenced by li in the enclosing scope.

In p2, on the other hand, i+=10 does assign a value to the local variable i, not the variable int1 in the enclosing scope. This is because the += operator on objects of type int do not actually modify the object, but return a new object instead. (That is, for an int, i+=10 is equivalent to i = i + 10.)


Just to show that += can operate on the underlying object directly, consider this function:

def p3(list1):
    list1 += [10]

Then run it on a list:

>>> foo = [1,2,3]
>>> p3(list1)
>>> foo
[1, 2, 3, 10]

Here, the call list1 += [10] is really equivalent to list1.extend([10]), not list1 = list1 + [10], due to how list.__iadd__ is defined. Here, you are again not assigning a value to the name list1, but rather invoking a method on the object referenced by list1 (which is the same object referenced by foo).

(Update: as pointed out by user2357112, technically you do assign to list1, but list.__iadd__ is designed to properly assign the same list back, so that the end result is that you still have a reference to the same mutable object you started with.)

Upvotes: 5

kpie
kpie

Reputation: 11080

A list is like a pointer to a list object.

#For example
a =[0,0]
b = a
b[0]=1

resulting in

b 
[1,0]

Where as an int is an a different beast

#For Example
a = 0
b = a
b +=1

resulting in

a 
1

to get the int behaviour from a listyou can make a clone of a list by passing it to list()

#for example
a = [0,0]
b = list(a)
b[0]=1

resulting in

a
[0,0]

and if you want the list behaviour from an int I guess you would have to just put it in a list.

Upvotes: -1

user2357112
user2357112

Reputation: 280251

Assigning to a variable, like i+=10, is an operation on a variable, while index assignment, like list1[0]=1000, is an operation on the object a variable refers to.

When you call p2(int1), the local variable i gets set to refer to the int int1 referred to, and then the i+=10 statement redirects i to refer to a new, larger integer. int1 still refers to the old integer.

When you call p1(li), the local variable list1 gets set to refer to the list li referred to, and then the list1[0]=1000 statement sets the first cell of the list to refer to 1000. li still points to this list throughout the modification, and after the function returns, li still reflects the change.

(There's another complexity here in that += also requests that an object mutate itself if it's mutable, in addition to performing an assignment, but that doesn't come up in this code.)

Upvotes: 3

Related Questions