Passing by assignment: Python

Viewed 146

I wanted to make sense of the following code variations:

a = [1, 2, 3]
b = a
b.append(4)
b = ['a', 'b']
print(a, b)

What I understood was that variable a refers to an object that contains the list [1,2,3] in some place in memory, and b now is referring to the same object that a is referring to, and via that link we're technically appending in a not b.

Output: [1, 2, 3, 4] ['a', 'b']

I updated the code a bit:

a = [1, 2, 3]
b = ['a', 'b']
b = a
b.append(4)
print(a, b)

My understanding: b is now referring to two objects, the first list ['a','b'] and the second list (that a is initially referring to) [1,2,3] via the third line b = a.

Output: [1, 2, 3, 4] [1, 2, 3, 4]

Last Code variation:

a = [1, 2, 3]
b = ['a', 'b']
b = a
b.append(4)
a.append(10)
print(a, b)

based on my understanding so far, I though that the link on line 3 b = a was giving only b the ability to reference multiple objects (it's own and a's) and a should've only be referencing one object [1,2,3], so the expected output should be: [1,2,3,4,10] [1,2,3,4]

Actual Output: [1, 2, 3, 4, 10] [1, 2, 3, 4, 10]

So is this assignment on line 3 b = a is like a bi-directional link? where also a reference is created by a to b's object?

I hope someone can clear this confusion for me and correct me on my thoughts if I was wrong. Thank you.

3 Answers

My understanding: b is now referring to two objects, . . .

That is not correct. A name cannot be associated with multiple objects within a given scope at the same time.

b = a associates b with the object that a is associated with. After that line has executed, nothing will be referencing ['a', 'b'], and that list should be eligible for garbage collection because it can no longer be used.

Don't think of the objects like pointers, I think that is the source of your confusion. It is not that "b points to a" or "a points to b", it has to do with binding to an object. I think looking at id will be useful

>>> a = [1, 2, 3]
>>> id(a)
1833964774216
>>> b = a
>>> id(b)
1833964774216

In this case both a and b are bound to that list. So any mutation to list 1833964774216 will be reflected in both objects. But I can re-assign (or re-bind) to a completely different object

>>> b = [4, 5, 6]
>>> id(b)
1833965089992
>>> b
[4, 5, 6]

This has no effect whatsoever on a because it is still bound to the original list

>>> a
[1, 2, 3]
>>> id(a)
1833964774216

let’s understand the difference between names and objects. In your case, a and b are names, and the list "[1,2,3]" assigned to a and b is the object. Initially a = [1,2,3] and after a is assigned to b i.e. b=a, in this case both a and b are bound to the same list object. This means that you can change that list object’s value by using either of the names a or b.

This can be overcome by copying the list assigned to a to b as,

b = a.copy()

which will create a copy of same object assigned to b

Related