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?
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With