GoodWilly
GoodWilly

Reputation: 173

Variable change in a function - Python 3

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

Answers (2)

Agost Biro
Agost Biro

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

Imperishable Night
Imperishable Night

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 ints, strs 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 ints, and formatting for strs --- you sometimes just need to get familiar with the peculiarities of different types.

Upvotes: 2

Related Questions