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