-2

I did a quickie test to confirm that making a copy of a list in Python using the '=' operator is really pointing to it, as opposed to its own copy...

x = [1, 2, 3]
print("x is: " + str(x) + " - " + str(id(x)))
y = x
print("y is: " + str(y) + " - " + str(id(y)))
x = [555, 666]
print("x is NOW: " + str(x))
print("y is NOW: " + str(y))

But the result ended up being...

x is: [1, 2, 3] - [string of numbers]
y is: [1, 2, 3] - [IDENTICAL string of numbers]
x is NOW: [555, 666]
y is NOW: [1, 2, 3]

This seems to indicate that x and y are now 2 separate lists? But their object ID's match to indicate that they're the same memory address. This seems inconsistent, and I feel like I'm missing something really obvious here!

ackmondual
  • 385
  • 3
  • 12
  • 1
    It's always worked that way. You're still not making a copy, but you don't notice, because `x = [555, 666]` isn't modifying the list; it's rebinding a name. – user2357112 Oct 13 '17 at 18:42
  • 3
    See https://nedbatchelder.com/text/names.html – user2357112 Oct 13 '17 at 18:42
  • 1
    Check the IDs again after changing x – Dalvenjia Oct 13 '17 at 18:43
  • No, **assignment never makes a copy**. You assigned to `x` again, so now it `x` refers to *a new list*. – juanpa.arrivillaga Oct 13 '17 at 18:47
  • replace `x = [555, 666]` with `x[0], x[1] = 555, 666` and you should see the behavior you expect. The answers on this question have a more thorough answer: https://stackoverflow.com/questions/240178/list-of-lists-changes-reflected-across-sublists-unexpectedly – MackM Oct 13 '17 at 18:47
  • You could also try `x[:] = [555, 666]`. This assigns to the slice of all of `x`. This is more flexible as it works just as well when you don't know the length of `x` or the RHS. (Also, `x = y[:]` can be used to effectively copy `y` if it's a one-dimensional list of integers). – Izaak van Dongen Oct 13 '17 at 19:00
  • user2357112, thanks for the link! I might have been misremembering things, but going forward, I know using '=' does indeed work! – ackmondual Oct 13 '17 at 20:23

1 Answers1

2

The assignment operator in Python is not allocation, it is just setting a reference to an object.

This seems to indicate that x and y are now 2 separate lists?

Yes, that is

[1, 2, 3]

creates an object, a list, that contains the objects 1, 2, 3. Similarily,

[555, 666]

creates another list that contains the objects 555, 666. The assignment operation

x = y

merely says point x to the same object as y. There is no copying involved.

I feel like I'm missing something really obvious here

The thing to keep in mind is that Python's assignment operator (=) is setting the left-hand variable to be a reference to an object, while the allocation of the object is an explicit operation in itself. Assigning one variable to the value of an other means setting both variables to point to the same object.

But their object ID's match to indicate that they're the same memory address.

id() returns the id of the object the variable points to, not the id of the variable.

You can never change the value of an object by assigning it to a variable - if you want to change the content of the list pointed to by y, say, you have to use the subscription operator [i] where i is the 0-based index, e.g.

y[2] = 5
=> [1, 2, 5]

or for that matter any value-changing operation supported by the list object, e.g. del, append or extend.

some other method if you wanted x and y to be independent [asked in comments]

Here's a few ways

  1. x = [1, 2, 3]; y = [555, 666] - as in your example
  2. x = [1, 2, 3]; y = list(x) - both point to a different list object yet with the same content
  3. import copy; x = [[1], [2], [3]]; y = copy.deepcopy(x) - different list objects with different contents

Note that deepcopy makes a copy of every (mutable) object contained in the list, while immutable objects are not copied but referenced to the same objects (i.e. the objects 1, 2, 3 are still the same id() even after deepcopy because numbers are immutable).

miraculixx
  • 10,034
  • 2
  • 41
  • 60
  • I forgot to print the IDs for the 2nd time around. They are different from each other, whereas the "123" one is still the same. Shouldn't x and y still be the same? I ran similar code in the past, and they were the same, recalling that you need to use some other method if you wanted x and y to be independent of each other – ackmondual Oct 13 '17 at 20:10
  • @ackmondual *Shouldn't x and y still be the same* - no, as you're reassigning x to point to a new object, specifically the list created by `[555, 666]`, while y still points to the list created by `[1, 2, 3]`. See the update re. copying. – miraculixx Oct 15 '17 at 08:13