Reputation: 13892
I was looking at this guy's post: https://stackoverflow.com/a/2573965/1959054
He was talking about testing people's Python proficiency by asking them the outputs of the following code:
x = 42
y = x
x = x+1
print x
print y
x = [1,2,3]
y = x
x[0]=4
print x
print y
I predicted those two outputs successfully, having just read about similar scenarios with mutable lists and immutable strings in a book. Then he gave this example:
x = ["foo",[1,2,3],10.4]
y = list(x)
y[0] = 'foooooo'
y[1][0] = 4
print x
print y
This left me very confused. You see, I predicted that x
would print as ["foo",[1,2,3],10.4]
and y
would print as ["foooooo",[4,2,3],10.4]
.
x
actually printed as ["foo",[4,2,3],10.4]
, meaning that, even though the outside list was referencing different list
objects, the inner list at x[1]
and y[1]
was still referencing the same object.
I hadn't come across this before.
My primary question is, if you want to make y
equivalent to x
, but not reference the same list, and ALSO make sure any nested lists aren't referencing the same lists as well, how do you do that? y = list(x)
seems to only handle the outer list.
My secondary question is just to get any help conceptually understanding why this works this way.
Upvotes: 2
Views: 55
Reputation: 121975
Your first question is answered by copy.deepcopy()
, which (docs):
constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
from copy import deepcopy
y = deepcopy(x)
As to why this happens, the standard list construction from list()
(and the common slice
copy x[:]
) creates only a shallow copy, i.e. (docs again, emphasis mine):
constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
Upvotes: 1