Chained list assignment in python [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 4 years ago.
When I ran this script (Python v2.6):
a = [1,2]
b = a
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2,3]
I expected print b to output [1,2]. Why did b get changed when all I did was change a? Is b permanently tied to a? If so, can I make them independent? How?

Memory management in Python involves a private heap memory location containing all Python objects and data structures.
Python's runtime only deals in references to objects (which all live in the heap): what goes on Python's stack are always references to values that live elsewhere.
>>> a = [1, 2]
>>> b = a
>>> a.append(3)
Here we can clearly see that the variable b is bound to the same object as a.
You can use the is operator to tests if two objects are physically the same, that means if they have the same address in memory. This can also be tested also using the id() function.
>>> a is b
>>> True
>>> id(a) == id(b)
>>> True
So, in this case, you must explicitly ask for a copy.
Once you've done that, there will be no more connection between the two distinct list objects.
>>> b = list(a)
>>> a is b
>>> False

Objects in Python are stored by reference—you aren't assigning the value of a to b, but a pointer to the object that a is pointing to.
To emulate assignation by value, you can make a copy like so:
import copy
b = copy.copy(a)
# now the code works as "expected"
Be aware this has performance disadvantages.
In the case of an array, there's a special method that relies on slices:
b = a[:]
# code also works as expected here
Update– In addition to this, with some objects you can use the constructor—this includes lists:
b = list(a)

Short answer - Pointers.
When you type b = a it is setting b to look at the same array that a looks at. You have to make a new array with copies of the elements to separate them. In this case, something like b = [n for n in a] would work fine. For more complex operations you may want to check out http://docs.python.org/library/copy.html.

You might want to look at this link. The problem you have here is a and b both point to the same memory location, so changing one changes the other. Instead, you want to do something like this:
a = [1,2]
b = list(a)

a is a pointer to the list [1,2].
When you do the assignment b = a the value of b is the address of the list [1,2].
So when you do a.append(3) you are not actually changing a, you are changing the list that a points to. Since a and b both point to the same list, they both appear to change when you modify the other.

If you simply want to copy the contents of list a to b, instead of making b a pointer to a:
b = a[:]
Using the slice operator will copy the contents of the list into b such that you example would become:
a = [1,2]
b = a[:]
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2]

Related

If the elements of the list point to same memory address, how are the two list not referring to the same object?

I initialize two lists as follows:
>>> a = [1]
>>> b = [1]
Then I find the memory location of the elements at index 0 for both the lists:
>>> id(a[0])
93961440619840
>>> id(b[0])
93961440619840
The address of both the element is the same. But when I try to find out if both the lists are referring to the same object, I get 'False'
>>> a is b
False
My question is, if the elements of the list refers to the same memory, why do the list not refer to the same object?
My question is, if the elements of the list refers to the same memory, why do the list not refer to the same object?
Because lists are mutable objects, so each list literal has to create a brand new list object independent from every previous one^[0]. Otherwise
>>> a = []
>>> b = []
>>> a.append(1)
>>> print(b)
would print [1] rather than the empty list, which would be insane.
The reason why id(a[0]) and id(b[0]) are the same despite being different literals is that Python can preallocate / intern frequently used immutable objects to lower memory consumption.
This is an implementation detail which must not be relied upon as it's an internal property of a specific implementation and it can change at any time. Currently, CPython will preallocate all integers between -5 and 256 (included), so these will always be the same objects even if you create them via independent literals or via computations.
[0] technically cpython (again internal detail of a specific implementation) maintains freelists of objects, so when a list is "collected" it's really stored away so the allocation can be reused next time we need a list instead of having to reallocate and setup a brand new one. This means different list used consecutively (but not concurrently) can have the same id, even if there are lots of other allocations in the meantime.
Only the memory location of the elements at index 0 are equal, not the memory address of the whole lists.
a[0] is b[0] # This returns True
The memory location of the entire lists are different: you can test so by typing
id(a)
id(b)
Python does so to reduce the memory usage
If you check a[0] is b[0] then it will be True. Since the element of a[0] and b[0] are the same and that's why those ids also the same. The result is True.
a = [1]
b = [1]
print(a[0] is b[0])
print(id(a[0]), id(a[0]))
# Output
# True
# 1793259440 1793259440
Now why a is b is False? Becasue a and b are distinct list and have distinct id
print(a is b)
print(id(a), id(b))
# Output
# False
# 9997064 9997800
a and b are different objects, so id(a) is not equal to id(b)
but a[0] is constant 1, which equals to b[0], and their addresses are the same, to save memory.
Help this helps.

Uniting 2 sets works not the way I expected in python [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 4 years ago.
When I ran this script (Python v2.6):
a = [1,2]
b = a
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2,3]
I expected print b to output [1,2]. Why did b get changed when all I did was change a? Is b permanently tied to a? If so, can I make them independent? How?
Memory management in Python involves a private heap memory location containing all Python objects and data structures.
Python's runtime only deals in references to objects (which all live in the heap): what goes on Python's stack are always references to values that live elsewhere.
>>> a = [1, 2]
>>> b = a
>>> a.append(3)
Here we can clearly see that the variable b is bound to the same object as a.
You can use the is operator to tests if two objects are physically the same, that means if they have the same address in memory. This can also be tested also using the id() function.
>>> a is b
>>> True
>>> id(a) == id(b)
>>> True
So, in this case, you must explicitly ask for a copy.
Once you've done that, there will be no more connection between the two distinct list objects.
>>> b = list(a)
>>> a is b
>>> False
Objects in Python are stored by reference—you aren't assigning the value of a to b, but a pointer to the object that a is pointing to.
To emulate assignation by value, you can make a copy like so:
import copy
b = copy.copy(a)
# now the code works as "expected"
Be aware this has performance disadvantages.
In the case of an array, there's a special method that relies on slices:
b = a[:]
# code also works as expected here
Update– In addition to this, with some objects you can use the constructor—this includes lists:
b = list(a)
Short answer - Pointers.
When you type b = a it is setting b to look at the same array that a looks at. You have to make a new array with copies of the elements to separate them. In this case, something like b = [n for n in a] would work fine. For more complex operations you may want to check out http://docs.python.org/library/copy.html.
You might want to look at this link. The problem you have here is a and b both point to the same memory location, so changing one changes the other. Instead, you want to do something like this:
a = [1,2]
b = list(a)
a is a pointer to the list [1,2].
When you do the assignment b = a the value of b is the address of the list [1,2].
So when you do a.append(3) you are not actually changing a, you are changing the list that a points to. Since a and b both point to the same list, they both appear to change when you modify the other.
If you simply want to copy the contents of list a to b, instead of making b a pointer to a:
b = a[:]
Using the slice operator will copy the contents of the list into b such that you example would become:
a = [1,2]
b = a[:]
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2]

changing the value of var1 [duplicate]

This question already has an answer here:
Understanding mutability in Python [closed]
(1 answer)
Closed 9 years ago.
My question is more of an understanding question than a strict programming question.
I know that python variables are actually pointers, which means they don't actually store a value, but rather point to the place in memory where that value is stored.
What i can't figure out is how the following 2 cases differ:
>>> a = 3
>>> b = a
>>> a
3
>>> b
3
>>>b = 4
>>> b
4
>>> a
3
The new value assigned to 'b' does not change the value pointed to by 'a'. As oppose to:
>>> a = [1,2,3]
>>> b = a
>>> a
[1,2,3]
>>> b
[1,2,3]
>>> b.append(4)
>>> b
[1,2,3,4]
>>> a
[1,2,3,4]
The new value assigned to b changed the value pointed to by a
Calling b.append doesn't assign b to a new list. It still points to the same position in memory.
>>> b = [1,2,3]
>>> id(b)
36586568L
>>> b.append(4)
>>> id(b)
36586568L
Since it is the underlying data that changes, any other identifiers also pointing to that data will be affected.
This has been covered many times before. Short answer is that they aren't strictly pointers. They are more like labels. In your top case, b is re-labeled to 4 and thus changes. In your bottom case (with the array) b is not re-labeled, but only it's contents appended to. That's why arrays seem to act differently.
Python "variables" ("binding" would be a more appropriate term) are not pointers, they are key->value pairs in a namespace. How the namespace and lookup are implemented is, well, an implementation detail, but you can consider it's a hash table (Python's dict).
The new value assigned to b changed the value pointed to by a
Where do you see the assignement operator in b.append(4) ? You're not rebinding b, you are mutating it. It's still the same list object that is bound to both names a and b.

python: list changes when global edited

a = [1]
def do():
global a
b=a
print b
a[0] = 2
print b
do()
outputs:
1
2
I am pretty sure it has something to do with the fact that 'a' is a global list.
Could someone please explain to me why the variable b changes when the global changes. And how i could possibly stop it from happening?
an extension to the question:
how would you handle further nesting, such as:
a = []
b = []
def do():
global a, b
b.append(a[:])
print a, b
a[0][0] +=1
print a, b
a.append([1])
do()
In this line b=a you essentially create a reference b, which points to a. This in python does not create a new copy of the list, but just creates a new link to it.
If you want to create a copy of a then you need to do it explicitly. Using list comprehensions, you can do it in this way :
b = a[:]
This will create a copy of a which will be referenced by b. See it in action :
>>> a = [1]
>>> b = a #Same list
>>> a[0] = 2
>>> b
[2] #Problem you are experiencing
You can see for yourself whether they refer to the same object or not by :
>>> a is b
True
The true signifies that they refer to the same object.
>>> b = a[:] #Solution <<--------------
Doing the same test again :
>>> a is b
False
And problem solved. They now refer to different objects.
>>> b
[2]
>>> a[0] = 3 #a changed
>>> a
[3]
>>> b
[2] #No change here
When you assign b = a you are copying the reference to a list object that is held in a to b, so they point at the same list. The changes to the underlying object will be reflected by either reference.
If you want to create a copy of the list use
b = list(a)
or, a method that will work on most objects:
import copy
b = copy.copy(a)
I think you have a misunderstanding of python's variable model. This is the article I read that made it click for me (the sections "Other languages have variables" and "Python has names").

Difference between a[:] = b and a = b[:]? (Python)

I was asked this for a coding test and didn't know the answer. Anyone have any ideas?
[:] is the slice operator.
When it's on the left side, it overwrites the contents of the list without creating a new reference.
When it's on the right side, it creates a copy of the list with the same contents.
a = b[:] calls either __getslice__ or __getitem__ on b and assigns the result to a. In nearly all cases (e.g. lists, tuples, and other sequence types), this makes a shallow copy of the sequence; I don't know of any classes that don't implement that behavior, but you could have a user-defined type that did something different. Any other objects that previously referred to the old value of a will continue to refer to that old value.
a[:] = b, on the other hand, calls __setslice__ or __setitem__ to replace a subset of the elements of a with those of the sequence b. In this case, if the sequence type of a is well-behaved, this will replace the entirety of a, since the range : without endpoints indicates the entire sequence. The difference here is that immutable types, such as tuples, will not allow you to perform __setslice__ (e.g. by throwing a TypeError exception). Any other objects that previously referred to a will also be updated, since the underlying object is being modified.
For mutable types such as list, the result of a = b[:] will be identical to a[:] = b, in that a will be a shallow copy of b; for immutable types such as tuple, a[:] = b is invalid. For badly-behaved user-defined types, all bets are off. There's also a difference in what happens to other objects that referred to the same object as a -- with a = b[:], they refer to the original value (a), but with a[:] = b, they refer to the modified object (shallow copy of b).
In both cases you end up the list a being a copy of the list b. But the method used to accomplish this has changed.
a[:] = b modifies the list a so that it has the same elements as b
a = b[:] produces a new list which is a copy of b and replaces the list a
The difference is whether we've modified an existing list or created a new one.
To see the difference:
a = range(3)
b = range(4)
c = a # c and a now share the same list
a[:] = b
print "a", a
print "b", b
print "C", c
All three lists will print out the same. C and a share the same object, so when a was modified so was c
a = range(3)
b = range(4)
c = a # c and a now share the same list
a = b[:]
print "a", a
print "b", b
print "C", c
Now c will not print out the same as a. After the assignment, a and c did not share the same object.
Speedwise, a[:] = b is probably a little faster than a = b[:]. The first form doesn't have to create a new list object, it can merely modify the existing list. A big part of this is that it can reuse the memory already owned by the list rather then allocating new memory.

Categories

Resources