I'm trying to create a list that holds the coordinates of an object.
crds = [0,0,0]
class create:
line = [["!PlacementError!"] for i in range(0, 8)]
def lineIterate():
for i in range(0, len(create.line)):
print(i)
crds[0] = i 0
print(create.line)
create.line[i] = crds
print(create.line)
print(create.line[i])
When I run the code it writes to each index but also all previous indices.
0 [[0, 0, 0], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!']]
1 [[1, 0, 0], [1, 0, 0], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!']]
What is should be: [[0, 0, 0],[1, 0, 0]]
CodePudding user response:
In your code there is only one crds
list, which you mutate and repeatedly reference in the line
array. But since it is only one list, when you mutate it, you actually mutate the list that you already assigned to line[i]
in a previous iteration.
The solution is to create a new list in each iteration, so that line
will get references to separate lists, not the same one. For instance, you could create a copy on each assignment to line[i]
:
create.line[i] = crds[:]
CodePudding user response:
It's seems that you put crds = [0,0,0]
in line[0]
, and then you changed the crds
from [0,0,0]
to [1,0,0]
, and you put the new(actually not) crds
to line[1]
.
you may think that the line should be like: [[0,0,0], [1,0,0]]
.
Python uses the Shallow Copy, so when you let an element of line
equal to crds
, python just created a link
from the element to crds
, your line
is actually: [crds, crds, crds...]
, when you change element in crds
, all the element in line
will be changed.
by using id()
function you can get the id of the object in python.
print(' id of crds:', id(crds))
print('element id in line:',list(map(id, create.line)))
id of crds: 2349824066880
element id in line: [2349824066880, 2349824066880, 2349824066880, 2349824066880, 2349824066880, 2349824066880, 2349824066880, 2349824066880]
this may be what you want:
class Creat(object):
"""docstring for Creat"""
def __init__(self):
super(Creat, self).__init__()
self.line = [["!PlacementError!"]]*8
def lineIterate(self):
for i in range (0, len(self.line)):
self.line[i] = [i, 0, 0]
print(self.line)
if __name__ == '__main__':
c = Creat()
c.lineIterate()
>>> [[0, 0, 0], [1, 0, 0], [2, 0, 0], [3, 0, 0], [4, 0, 0], [5, 0, 0], [6, 0, 0], [7, 0, 0]]
or you can use deepcopy
or line[i] = crds[:]
:
import copy
class Creat(object):
"""docstring for Creat"""
def __init__(self):
super(Creat, self).__init__()
self.line = [["!PlacementError!"]]*8
self.crds = [0, 0, 0]
def lineIterate(self):
for i in range (0, len(self.line)):
self.crds[0] = i 0
self.line[i] = copy.deepcopy(self.crds)
self.line[i] = crds[:] # the same as deepcopy
print(self.line)
if __name__ == '__main__':
c = Creat()
c.lineIterate()
>>> [[0, 0, 0], [1, 0, 0], [2, 0, 0], [3, 0, 0], [4, 0, 0], [5, 0, 0], [6, 0, 0], [7, 0, 0]]
Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other. Shallow and deep copy operations