Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reassigning variables in python [duplicate]

Tags:

python

I have the following code and variables, and I want to find what the variables a, a1, a2, b, b1, and b2 refer to after the code has been executed.

def do_something(a, b):
    a.insert(0, "z")
    b = ["z"] + b

a = ["a", "b", "c"]
a1 = a
a2 = a[:]
b = ["a", "b", "c"]
b1 = b
b2 = b[:]

do_something(a, b)

My attempted solution is as follows:

a = ["z", "a", "b", "c"]
a1 = ["a", "b", "c"]
a2 = ["a", "b", "c"]
b = ["z" "a", "b", "c"]
b1 = ["a", "b", "c"]
b2 = ["a", "b", "c"]

But the actual solution is:

a = ["z", "a", "b", "c"]
a1 = ["z", "a", "b", "c"]
a2 = ["a", "b", "c"]
b = ["a", "b", "c"]
b1 = ["a", "b", "c"]
b2 = ["a", "b", "c"]

Can anyone walk me through my mistake?

like image 731
Susie Avatar asked Apr 22 '15 22:04

Susie


1 Answers

Ok, you can think of variables in Python as references. When you do:

a1 = a

Both a1 and a are references to the same object, so if you modify the object pointed by a you will see the changes in a1, because - surprise - they are the same object (and the list.insert method mutates the list in place).

But when you do:

a2 = a[:]

Then a2 is a new list instance, and when you modify a you are not modifying a2.

The result of the + operator for lists is a new list, so when you do:

b = ['z'] + b

You are assigning a new list to b instead of mutating b in-place like you would do with b.insert('z'). Now b points to a new object while b1 still points to the old value of b.

But the scopes can be even trickier: you can see the enclosing scope from a function, but if you assign a variable inside the function, it will not change the variable with the same name in the enclosing (or global, or built-in) scope, it will create a variable with this name in the local scope. This is why b was not changed - well, not quite, parameter passing in Python is an assignment operation, so b is already a local variable when there is a parameter named b - but trying to mutate a variable defined in the enclosing scope leads to a similar problem. BTW, it is bad practice to rely on variables from the enclosing scope unless they are module-level constants (traditionally they are named in ALL_UPPERCASE style and you are not supposed to mutate them). If you need the value inside the function, pass it as a parameter, and it you want to change the value of the variable in the enclosing scope, return the value and assign the returned value there:

def do_something(a, b):
    a.insert(0, "z")  # mutates a in-place
    return ["z"] + b

b = do_something(a, b)
like image 153
Paulo Scardine Avatar answered Oct 16 '22 19:10

Paulo Scardine



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!