This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Why does a[0] change? [duplicate]
(1 answer)
Closed 7 years ago.
I am pretty confused with the difference in results of the Python codes below. Why in first case "a" does not change upon the change of "b", but in second one does?
a=b=[]
b = [1,2,3]
print b,a
########## compare with below ################################
a=b=[]
b.append([1,2,3])
print b,a
Result of first part is:
[1,2,3] [ ]
and result of the second part is:
[[1,2,3]] [[1,2,3]]
It was suggested that it is a duplicate question but I think here I am changing the list "b" with two different ways and I guess it could show how these two methods of variable manipulation could be different.
Because = is not the same as append.
When you do b = [1, 2, 3], you assign a new value to b. This does not involve the old value of b in any way; you can do this no matter what value b held before.
When you do b.append(...), you modify the object that is the existing value of b. If that object is also the value of other names (in this case, a), then those names will also "see" the change. Note that, unlike assignment, these types of operations depend on what kind of value you have. You can do b.append(...) because b is a list. If b was, say, an integer, you could not do b.append, but you could still do b = [1, 2, 3].
In the first example, you are reassigning the variable b, and now it points to another list.
a = b = [] # a -> [] <- b
b = [1, 2, 3] # a -> [], b -> [1, 2, 3]
In the second example, both a and b variables are pointing to the same list, and you are inserting values in the list:
a = b = [] # a -> [] <- b
b.append([1, 2, 3]) # a -> [[1, 2, 3]] <- b
To elaborate on the other answers, this is straight from the Python docs:
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
Looking at:
a[len(a):] = [x]
it is easy to see that using append is modifying the original list (a in the python sample code, b in your case).
As the others people have pointed out, using an assignment statement is assigning a new value to b, instead of modifying it via append.
Related
This question already has answers here:
Remove list element without mutation
(8 answers)
Closed 2 years ago.
Is it possible to apply a method, for example remove, append, etc., to a list and assign it to a new list?
for example I want to remove the element 2 from list A = [1,2,3,4] and have a list B as [1,3,4]. somehow like the following:
B = A.remove(2)
How can I do this in python?
The easiest way would be
B = A[:]
B.remove(2)
Just copy A to B using copy.deepcopy and then remove 2 from B. Here is how you do it:
import copy
A = [1,2,3,4]
B= copy.deepcopy(A)
B.remove(2)
print(A)
print(B)
Output:
[1, 2, 3, 4]
[1, 3, 4]
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.
I am new to python, previously was using Matlab, and have some confusion regarding variables in python.
I am trying to rewrite a Matlab code in python, and here is where confusion happens. Lets say I have the following case:
>>> A = np.array([[1,2,3],[4,5,6]])
>>> out = np.array([[True, False, True],[False, True, False]])
>>>
>>> B = A
>>>
>>> B[out] = A[out]+1
>>>
>>> B
array([[2, 2, 4],
[4, 6, 6]])
>>> A
array([[2, 2, 4],
[4, 6, 6]])
In Matlab, A does not change with the same piece of code, but in python, it does. Anyone can explain why and what is the best way to avoid the change of A?
Code-image: why assigning A to B is kept in the flow?
By doing
B = A
you are creating another reference to the same object A so all the changes incurred by A will be automatically reflected in B. The proper (few) ways to copy the list/array in this case
B = A[::]
or
B = A.copy()
This way you copy the elements into a list variable without creating a pointer to the original variable A thereby decoupling them in term sof memory addresses.
As pointed out by Jon Clements,
[::] means start, end with a step size of 1 which means [0:len(obj):1] whereas [:] means [:len(obj)] where obj is your object.
As pointed out by #Patrick below, if you A is a numpy matrix, you can also do
B = np.copy(A)
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.
Here I have a vector a=[1,2,3,4,5]
a=b
a[0]=a[2]
print a
a=[2,2,3,4,5]
b=[2,2,3,4,5]
but I don't want vector b to be changed, I want it always b=[1,2,3,4,5]
Actually, you can regard b as the original vector of a.
Use copy funtion like this :
a=b.copy()
a[0]=a[2]
print a
a=[3,2,3,4,5]
b=[2,2,3,4,5]
for a list, a = b just copies the reference. So when you change one value of the list then the value of all variables (those hold the same reference) become changed. copy() or deepcopy() function actually copies the list. You can read this doc.
Update with your input :
b=[1,2,3,4,5]
a=b.copy()
a[0]=a[2]
print(a)
print(b)
It prints :
[3, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
Using list slicing in this case is weird but working one :
b=[1,2,3,4,5]
a=b[:]
a[0]=a[2]
print(a)
print(b)
This works the way I want
a = [1,8,10]
b = list([a])
a = [0,8,10]
b.append(a)
a = [0,0,10]
b.append(a)
print(b)
giving me the list that I want:
[[1, 8, 10], [0, 8, 10], [0, 0, 10]]
I need to change the values using variables based on the index of the list like this
a = [1,8,10]
b = list([a])
a[0] = a[0] - 1
b.append(a)
print(b)
and I get this result :
[[0, 8, 10], [0, 8, 10]]
My entire point is to keep track of my moves for creating the nim game. I think I see how setting a[0] = a[0] - 1 changes the value in both places even when I tried using deep copy but I am stumped on how else to get the answer. I am sure it is obvious but I don't know what key words to use to search for the solution, so please help me.
Using deepcopy should work -- I suspect you were just using it in the wrong place.
The danger of using a single list as a template, as you were doing with a is that if you mutate it, you could end up changing the lists you've already appended to b. One way to get around this problem is to always create a new copy of a whenever you want to change it.
import copy
b = []
a = [1,8,10]
b.append(a)
a2 = copy.deepcopy(a)
a2[0] = a2[0] - 1
b.append(a2)
print(b)
Another way might be to make a copy of a whenever you append it to b, so that you don't have to keep creating new variables:
import copy
b = []
a = [1,8,10]
b.append(copy.deepcopy(a))
a[0] = a[0] - 1
b.append(copy.deepcopy(a))
print(b)
The common point between these two different approaches is that we always append any given list exactly once. In your code, you append the same list multiple times to b. That means that whenever you change a, it appears as if you changed everything in b.
In the two examples I provided, I append a list only once, and copy it if I need to make changes. By doing so, I ensure that each list inside b is unique, and avoid running into the issue you encountered.
As a side note, another way to create a copy of a list is to do a2 = a[:]. The a[:] is telling Python to get a list slice of a starting from the beginning of the list to the end, essentially copying it. Note that this is a shallow copy, not a deep copy. However, since your lists contain only numbers, a shallow copy should work fine.
I want to change a in the for-loop to [4,5,6].
This code just print: 1, 2, 3
a = [1,2,3]
for i in a:
global a
a = [4,5,6]
print i
I want the ouput 1, 4, 5, 6.
You'll need to clarify the question because there is no explanation of how you should derive the desired output 1, 4, 5, 6 when your input is [1, 2, 3]. The following produces the desired output, but it's completely ad-hoc and makes no sense:
i = 0
a = [1, 2, 3]
while i < len(a):
print(a[i])
if a[i] == 1:
a = [4, 5, 6]
i = 0 # edit - good catch larsmans
else:
i += 1
The main point is that you can't modify the parameters of a for loop while the loop is executing. From the python documentation:
It is not safe to modify the sequence being iterated over in the loop
(this can only happen for mutable sequence types, such as lists). If
you need to modify the list you are iterating over (for example, to
duplicate selected items) you must iterate over a copy.
Edit: if based on the comments you are trying to walk URLs, you need more complicated logic to do a depth-first or breadth-first walk than just replacing one list (the top-level links) with another list (links in the first page). In your example you completely lose track of pages 2 and 3 after diving into page 1.
The issue is that the assignment
a = [4,5,6]
just changes the variable a, not the underlying object. There are various ways you could deal with this; one would be to use a while loop like
a = [1,2,3]
i = 0
while i<len(a):
print a[i]
a = [4,5,6]
i += 1
prints
1
5
6
If you print id(a) at useful points in your code you'll realise why this doesn't work.
Even something like this does not work:
a = [1,2,3]
def change_a(new_val):
a = new_val
for i in a:
change_a([4,5,6])
print i
I don't think it is possible to do what you want. Break out of the current loop and start a new one with your new value of a.