Reputation: 173
So I got the following code:
def foo(a, b, c):
try:
a = [0]
b[0] = 1
c[0] = 2
w[0] = 3
except:
pass
return z
x, y, z = [None], [None], [None]
w = z[:]
foo(x,y,z)
print(x,y,z,w)
The last line of the code print(x,y,z,w)
prints [None] [1] [2] [3]
, however
I don't quite get it. Why are x,y,z
are being changed from within the funciton? and if w
changes - and it points to z
, why doesnt z
change accordingly?
Upvotes: 1
Views: 414
Reputation: 2839
In Python objects are passed by reference to functions.
This line makes a copy of z
w = z[:]
so changes to z
don't affect w
and vice versa. In the line
a = [0]
you change the reference to point to a new object, so you don't mutate x
(which is what a
was initially bound to). In the following lines
b[0] = 1
c[0] = 2
you mutate the objects that you got references to (y
and z
in global scope), so the objects in the outside scope change. In the line
w[0] = 3
you mutate the global object w
since the name w
is not a parameter of the function, nor is it bound in the body of the function.
Upvotes: 4
Reputation: 1533
What everyone else says is correct, but I want to add my way of thinking that may be helpful if you have experience with a language like C or C++.
Every variable in Python is a pointer (well, the technical term is a "reference", but I find that more difficult to visualize than "pointer"). You know how in C/C++ you can get a function to output multiple values by passing in pointers? Your code is doing essentially the same thing.
Of course, you may be wondering, if that is the case, why don't you see the same thing happening to int
s, str
s or whatnot? The reason is that those things are immutable, which means you cannot directly change the value of an int
or a str
at all. When you "change an integer", like i = 1
, you are really changing the variable, pointing it to a different int
object. Similarly, s += 'abc'
creates a new str
object with the value s + 'abc'
, then assigns it to s
. (This is why s += 'abc'
can be inefficient when s
is long, compared to appending to a list!)
Notice that when you do a = [0]
, you are changing a
in the second way --- changing the pointer instead of the object pointed to. This is why this line doesn't modify x
.
Finally, as the others has said, w = z[:]
makes a copy. This might be a little confusing, because for some other objects (like numpy arrays), this syntax makes a view instead of a copy, which means that it acts like the same object when it comes to changing elements. Remember that []
is just an operator, and every type of object can choose to give it a different semantical meaning. Just like %
is mod for int
s, and formatting for str
s --- you sometimes just need to get familiar with the peculiarities of different types.
Upvotes: 2