This question already has answers here:
Changing one list unexpectedly changes another, too [duplicate]
(5 answers)
Changing an element in one list changes multiple lists [duplicate]
(4 answers)
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
How to deep copy a list?
(10 answers)
Closed 5 years ago.
Here is my code:
x = [[1],[1],[1],[-1]]
a = [[-2,-1,-1,-2],[1,-2,2,-1],[-1,-2,-2,-1],[2,-1,1,-2]]
h = 0.1
def K(h,a,x):
cont = [1,2,3,4]
k = []
for i in range(len(cont)):
k.append(h*cont[i])
y = x
print('original value',x)
for j in range(len(y)):
y[j][0] += k[j]/4
print('modified value',x)
K(h,a,x)
So the question is why did the value of x change if it has not received anything?
When you put:
y = x
All x is doing is acting as a pointer to the list object in memory. When you do the above, you are saying I want y to point to the same list that x references in the memory. Any changes in place changes to y will also affect x.
If you wish to have the reference y point to a different object in memory (with the same values as x,) you need to make a copy of x.
y = x[:] #make a copy. SEE EDIT
Now y and x will be pointing to different list objects in memory, but both objects will have the same values.
Note that any mutable datatype in python shares this reference property, such as: sets, dictionaries, lists, byte arrays and also some classes.
Look into the differences between mutable and immutable datatypes in python as this distinction is critical and will lead to undiagnosible bugs without knowledge on how python accesses different data types.
EDIT!!
Sorry, I did not notice x is made of a series of lists. You need to use deepcopy to copy the nested lists!
from copy import deepcopy
y = deepcopy(x)
When you write:
y = x
You're literally saying that x equals y. This doesn't make a copy of x. Whatever you do to x will happen to y and vice versa. You need to make a copy of x if you want them to be independent.
Related
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 3 years ago.
I am trying to make a simple game of minesweeper without using OOP and have two lists: one holding the values of the table ('board[]') and one that should be empty for now ('revealed[]').
When i create an empty list of the right size in board_create() and append it to both lists the values in list 'revealed[]' change whenever I change the values in 'board[]'.
Yes, running the function for just 'revealed[]' does work but I just want to know why exactly this happens.
board = []
revealed = []
board_size = []
#creates board with size x,y
def board_create(x, y):
global revealed
global board
global board_size
board = []
board_size = [x, y]
for i in range(y):
out = []
for j in range(x):
out.append(0)
board.append(out)
revealed.append(out)
board_create(3,3) would output
'board = [[0,0,0],[0,0,0],[0,0,0]]' and 'revealed = [[0,0,0],[0,0,0],[0,0,0]]'
and when i change values in 'board[]' it should be
'board= [[0,1,x],[0,1,1],[0,0,0]]' (for example) and 'revealed = [[0,0,0],[0,0,0],[0,0,0]]'
not
'board= [[0,1,x],[0,1,1],[0,0,0]]' and 'revealed = [[0,1,x],[0,1,1],[0,0,0]]'
board.append(out)
revealed.append(out)
What you append here to board and revealed is not a copy of out, but a reference. Thus, any change you make in out by changing revealed is reflected in board. To copy out, use a slice: out[:]. See more on this topic here: Python FAQ
This question already has answers here:
Why does += behave unexpectedly on lists?
(9 answers)
Closed 6 years ago.
I don't understand why these functions give different results; I thought that s+= and s=s+ were equivalent:
def foo(s):
s += ['hi']
def foo2(s):
s = s + ['hi']
But the first modifies the list s and the second does not. Could someone help me clarifying this?
x+= y is same as x = x + y only for immutable types. For mutable types, the option exists to alter the object in-place. So for lists, += is the same as list.extend() followed by a re-bind of the name.
Read: Augmented Assignment Statements and Why does += behave unexpectedly on lists? for more information.
Use list.append because if you say s = s +['hi'] then s just point to another object, but if you use .append() then the same list is being changed
This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 7 years ago.
In detail, my question is this:
Given the following code,
x = 10
def func(x):
x = x+1
def main():
print(x)
func(x)
print(x)
if __name__ == '__main__':
main()
On running this I get:
10
10
Does this mean that Python does not pass values by reference?
And I did check through the other question of the sort, and most(if not all) included analogies of lists or other such examples.
Is it possible to explain this in simple terms, like just a simple integer?
Ps. I am a beginner to coding.
Thanks
If you are coming from a background such as C or C++, which I did, this can be maddening until you figure it out.
Python has names, not variables, and names are bound to objects. Effectively, you can think of all 'variables' or names, as being pointers to python objects.
In python, integers, floats, and strings are immutable. So when you do the following:
x = 10
x = x + 1
You are first binding the name x to the integer 10, then when you evaluate x + 1 you get a new object 11 and then you bind x to that object. Your x inside the function body is local to the function, and when you bind it to 11, the global x remains bound to 10.
If you were to pass a list to the function, and append something to the list, that list would be modified. A list in python is a mutable object. All names bound to the list would refer to the modified list.
As a result, when you pass mutable objects it may seem as if you are passing by reference, and when you pass immutable objects it may seem like you are passing by value.
This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Why does this code for initializing a list of lists apparently link the lists together? [duplicate]
(1 answer)
Closed 8 years ago.
I have a list that needs to contain a variable number of independent sets.
When I run the following piece of code, I want to add the string "testing" to only the first set.
numberOfSets = 3
test = [set()]*numberOfSets
test[0].add("testing")
print test
However, when I print test, it shows three identical sets that all contain testing. How can I set up my list so I can separately access each set?
When you do [set()]*3, you create three sets that reference the same object, thus when you change one value, the others change. Use a list comprehension here instead:
>>> numberOfSets = 3
>>> test = [set() for _ in xrange(numberOfSets)]
>>> test[0].add("testing")
>>> print test
[set(['testing']), set([]), set([])]
You can do
test = [set() for _ in xrange(numberOfSets)] # use 'range' in Python 3.x
[set()]*x creates a list with x of the same set instance, whereas the comprehension above creates a new, independent set on each iteration, as desired.
In general, you should be very cautious whenever you multiply lists whose elements are mutable.
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 9 years ago.
I am trying to get an element from list and make some change on this element (which is also a list). Weirdly, the change applied on the previous list. Here is my code:
>>>sentences[0]
['<s>/<s>',
'I/PRP',
'need/VBP',
'to/TO',
'have/VB',
'dinner/NN',
'served/VBN',
'</s>/</s>']
>>>sentence = sentences[0]
>>>sentence.insert(0,startc); sentence.append(endc)
>>>sentences[0]
['<s>/<s>',
'<s>/<s>',
'I/PRP',
'need/VBP',
'to/TO',
'have/VB',
'dinner/NN',
'served/VBN',
'</s>/</s>'
'</s>/</s>']
It is like I just got a pointer to that element, not a copy
You do get a "pointer", in fact. Lists (and any mutable value type!) are passed around as reference in Python.
You can make a copy of a list by passing it to the list() object constructor, or by making a full slice using [:].
a = [1,2,3]
b = a
c = list(a)
d = a[:]
a[1] = 4 # changes the list referenced by both 'a' and 'b', but not 'c' or 'd'
You're exactly right! In Python, when you pass a list as an argument to a function, or you assign a list to another variable, you're actually passing a pointer to it.
This is for efficiency reasons; if you made a separate copy of a 1000-item list every time you did one of the aforementioned things, the program would consume way too much memory and time.
To overcome this in Python, you can duplicate a one-dimensional list using = originalList[:] or = list(originalList):
sentence = sentences[0][:] # or sentence = list(sentences[0])
sentence.insert(0,startc)
sentence.append(endc)
print(sentence) # modified
print(sentences[0]) # not modified
Consider using list comprehension if you need to duplicate a 2D list.