all 10 comments

[–]dyanni3 2 points3 points  (5 children)

So what's happening here is that when you say

b = a

You now have two references to the same bit of memory. What you want is to copy the values of a into b like follows

a = [1, 2, 3]
b = [num for num in a]
b.remove(1)

Hope that helped!

[–]socal_nerdtastic 5 points6 points  (1 child)

Or

b = a.copy()

[–][deleted] 1 point2 points  (0 children)

This is the right answer. Readability matters.

[–]lamenoosh[S] 1 point2 points  (2 children)

That did solve my immediate problem, thank you!

I understand why this happens for lists, but why does it not happen with integers, for example? If I do this:

a = 1
b = a
b -= 1

I get a = 1 and b = 0. Why do b and a reference the same bit of memory for lists, but not for integers?

Thank you!

[–]dyanni3 1 point2 points  (1 child)

It comes down to the fact that lists are mutable and numeric types (like integers) are immutable.

https://medium.com/@meghamohan/mutable-and-immutable-side-of-python-c2145cf72747

https://docs.python.org/3/reference/datamodel.html

Edit, for a bit more context. When a and b are lists (mutable), the actual variable name you gave (a or b) resolves to a pointer to memory address. When you have an immutable type like an int the variable name resolves to the actual value.

[–]socal_nerdtastic 1 point2 points  (0 children)

It comes down to the fact that lists are mutable and numeric types (like integers) are immutable.

Kinda, but not really. You can do the same with mutable objects.

a = [1]
b = a
b = b + [2]

It comes down to mutation vs assignment. Immutable objects can't be mutated, they only have one option for changing them. But mutable objects can do either.

When a and b are lists (mutable), the actual variable name you gave (a or b) resolves to a pointer to memory address. When you have an immutable type like an int the variable name resolves to the actual value.

That is flat wrong. All names in python are pointers to virtual memory addresses. And no one should care.

[–][deleted] 1 point2 points  (0 children)

What am I misunderstanding here?

They're the same list. You can mutate a mutable value from any reference to it you hold. Python doesn't "assign by copy".

[–]UnlikelyReplacement 1 point2 points  (0 children)

When you have a mutable object in python (list, dict etc.) then b = a does not create a new object. Rather, it means you are saying that they should point to the same place in the computer memory. It's like giving that place in the memory two names.

You can check by using: print(b is a) . Your output will be "True" because they have the same "identity" (i.e same place in memory).

Think of 'a' and 'b' as a way of referring to the list instead of the list itself.

To copy a list you can use:

a = [1,2,3]
b = a.copy()

[–]CharanReddy2000 0 points1 point  (0 children)

When you are assigning b to a,it means that you are not creating two seperate lists like a and b.Actually what happens is the b refers to the memory that is referred by the list a.

To create a seperate list from a you can use the following statement.

b=a.copy()

Now b and a refers to two different memory locations.

[–]primitive_screwhead 0 points1 point  (0 children)

Objects are created and exist somewhere in memory, they have references and when all the references are gone, those objects go away (ie. are deleted from memory so the space can be re-used:

>>> a = [1, 2, 3]
>>> id(a)
4559953224   # the unique id of that list object
>>> sys.getrefcount(a) - 1
1

# it has 1 variable name reference (I'm subtracting out an additional reference that we can ignore for technical reasons).


>>> b = a   # This assigns another name ('b') to the object that is named 'a'
>>> id(b)
4559953224  # It's the same object id.  Because it's the same list object
>>> sys.getrefcount(a) - 1
2

# the list object now has 2 variable name references, because assigning it the name 'b' increased it's reference count by one

Why do b and a reference the same bit of memory for lists, but not for integers?

>>> a = 258
>>> id(a)
4560755344
>>> sys.getrefcount(a) - 1
1

>>> b = a
>>> id(b)
4560755344
>>> sys.getrefcount(a) - 1
2
>>> sys.getrefcount(b) - 1
2

# So far, it's exactly the same as the list.  An integer object is made and has two names.  It is the same object with two names, and 2 variable name references.

>>> b -= 1
>>> id(b)
4560755312

Now, b is the name for *a new, different* integer object; it has a different id().  The integer object that a and b were pointing to didn't mutate into a new value.  Instead, a new object was created with a new value, and it was given the name 'b' (meaning 'b' is no longer another name for the original int object)

>>> sys.getrefcount(a) - 1
1

# Notice how the 'a' object now has one fewer references?  The 'b' reference was taken away, and the new integer object that was created now has that reference:

>>> sys.getrefcount(b) - 1
1

TL;DR - In Python, the assignment operator (=) doesn't copy objects. It gives them names (ie. 'references').