When you write [x]*3 you get, essentially, the list [x, x, x]. That is, a list with 3 references to the same x. When you then modify this single x it is visible via all three references to it:
To fix it, you need to make sure that you create a new list at each position. One way to do it is
[[1]*4 for _ in range(3)]
which will reevaluate [1]*4 each time instead of evaluating it once and making 3 references to 1 list.
You might wonder why * can’t make independent objects the way the list comprehension does. That’s because the multiplication operator * operates on objects, without seeing expressions. When you use * to multiply [[1] * 4] by 3, * only sees the 1-element list [[1] * 4] evaluates to, not the [[1] * 4 expression text. * has no idea how to make copies of that element, no idea how to reevaluate [[1] * 4], and no idea you even want copies, and in general, there might not even be a way to copy the element.
The only option * has is to make new references to the existing sublist instead of trying to make new sublists. Anything else would be inconsistent or require major redesigning of fundamental language design decisions.
In contrast, a list comprehension reevaluates the element expression on every iteration. [[1] * 4 for n in range(3)] reevaluates [1] * 4 every time for the same reason [x**2 for x in range(3)] reevaluates x**2 every time. Every evaluation of [1] * 4 generates a new list, so the list comprehension does what you wanted.
Incidentally, [1] * 4 also doesn’t copy the elements of [1], but that doesn’t matter, since integers are immutable. You can’t do something like 1.value = 2 and turn a 1 into a 2.
回答 1
size =3
matrix_surprise =[[0]* size]* size
matrix =[[0]*size for i in range(size)]
Creates a list that references the internal [1,1,1,1] 3 times – not three copies of the inner list, so any time you modify the list (in any position), you’ll see the change three times.
Alongside the accepted answer that explained the problem correctly, within your list comprehension, if You are using python-2.x use xrange() that returns a generator which is more efficient (range() in python 3 does the same job) _ instead of the throwaway variable n:
[[1]*4 for _ in xrange(3)] # and in python3 [[1]*4 for _ in range(3)]
Also, as a much more Pythonic way you can use itertools.repeat() to create an iterator object of repeated elements :
Python containers contain references to other objects. See this example:
>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]
In this b is a list that contains one item that is a reference to list a. The list a is mutable.
The multiplication of a list by an integer is equivalent to adding the list to itself multiple times (see common sequence operations). So continuing with the example:
>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]
We can see that the list c now contains two references to list a which is equivalent to c = b * 2.
>>> myList =[1]*4>>> myList
[1,1,1,1]>>> id(myList[0])4522139440>>> id(myList[1])# Same as myList[0]4522139440
>>> myList[1]=42# Since myList[1] is immutable, this operation overwrites myList[1] with a new object changing its id.>>> myList
[1,42,1,1]>>> id(myList[0])4522139440>>> id(myList[1])# id changed4522140752>>> id(myList[2])# id still same as myList[0], still referring to value `1`.4522139440
myList = [[1]*4] * 3 creates one list object [1,1,1,1] in memory and copies its reference 3 times over. This is equivalent to obj = [1,1,1,1]; myList = [obj]*3. Any modification to obj will be reflected at three places, wherever obj is referenced in the list.
The right statement would be:
myList = [[1]*4 for _ in range(3)]
or
myList = [[1 for __ in range(4)] for _ in range(3)]
Important thing to note here is that * operator is mostly used to create a list of literals. Although 1 is immutable, obj =[1]*4 will still create a list of 1 repeated 4 times over to form [1,1,1,1]. But if any reference to an immutable object is made, the object is overwritten with a new one.
This means if we do obj[1]=42, then obj will become [1,42,1,1]not[42,42,42,42] as some may assume. This can also be verified:
>>> myList = [1]*4
>>> myList
[1, 1, 1, 1]
>>> id(myList[0])
4522139440
>>> id(myList[1]) # Same as myList[0]
4522139440
>>> myList[1] = 42 # Since myList[1] is immutable, this operation overwrites myList[1] with a new object changing its id.
>>> myList
[1, 42, 1, 1]
>>> id(myList[0])
4522139440
>>> id(myList[1]) # id changed
4522140752
>>> id(myList[2]) # id still same as myList[0], still referring to value `1`.
4522139440
In simple words this is happening because in python everything works by reference, so when you create a list of list that way you basically end up with such problems.
To solve your issue you can do either one of them:
1. Use numpy array documentation for numpy.empty
2. Append the list as you get to a list.
3. You can also use dictionary if you want
print("myList:")for i, subList in enumerate(myList):print("\t[{}]: {}".format(i, id(subList)))for j, elem in enumerate(subList):print("\t\t[{}]: {}".format(j, id(elem)))
Then having this, run the following code to make everything more clear. What the code does is basically print the ids of the obtained objects, which
Return the “identity” of an object
and will help us identify them and analyse what happens:
print("myList:")
for i, subList in enumerate(myList):
print("\t[{}]: {}".format(i, id(subList)))
for j, elem in enumerate(subList):
print("\t\t[{}]: {}".format(j, id(elem)))
So now let us go step-by-step. You have x which is 1, and a single element list y containing x. Your first step is y * 4 which will get you a new list z, which is basically [x, x, x, x], i.e. it creates a new list which will have 4 elements, which are references to the initial x object. The net step is pretty similar. You basically do z * 3, which is [[x, x, x, x]] * 3 and returns [[x, x, x, x], [x, x, x, x], [x, x, x, x]], for the same reason as for the first step.
回答 9
我想每个人都解释发生了什么。我建议一种解决方法:
myList = [[1 for i in range(4)] for j in range(3)]
Noticed why doesn’t modifying the first element of the first list didn’t modify the second element of each list? That’s because [0] * 2 really is a list of two numbers, and a reference to 0 cannot be modified.
If you want to create clone copies, try Operation 3:
li = [0] * 3
print([id(v) for v in li]) # [140724141863728, 140724141863728, 140724141863728]
li[0] = 1
print([id(v) for v in li]) # [140724141863760, 140724141863728, 140724141863728]
print(id(0)) # 140724141863728
print(id(1)) # 140724141863760
print(li) # [1, 0, 0]
ma = [[0]*3] * 3 # mainly discuss inner & outer *3 here
print([id(li) for li in ma]) # [1987013355080, 1987013355080, 1987013355080]
ma[0][0] = 1
print([id(li) for li in ma]) # [1987013355080, 1987013355080, 1987013355080]
print(ma) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
Here is my explanation after trying the code above:
The inner *3 also creates references, but it’s references are immutable, something like [&0, &0, &0], then when to change li[0], you can’t change any underlying reference of const int 0, so you can just change the reference address into the new one &1;
while ma=[&li, &li, &li] and li is mutable, so when you call ma[0][0]=1, ma[0][0] is equally to &li[0], so all the &li instances will change its 1st address into &1.
回答 12
通过使用内置列表功能,您可以像这样
a
out:[[1,1,1,1],[1,1,1,1],[1,1,1,1]]#Displaying the list
a.remove(a[0])
out:[[1,1,1,1],[1,1,1,1]]# Removed the first element of the list in which you want altered number
a.append([5,1,1,1])
out:[[1,1,1,1],[1,1,1,1],[5,1,1,1]]# append the element in the list but the appended element as you can see is appended in last but you want that in starting
a.reverse()
out:[[5,1,1,1],[1,1,1,1],[1,1,1,1]]#So at last reverse the whole list to get the desired list
By using the inbuilt list function you can do like this
a
out:[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#Displaying the list
a.remove(a[0])
out:[[1, 1, 1, 1], [1, 1, 1, 1]]
# Removed the first element of the list in which you want altered number
a.append([5,1,1,1])
out:[[1, 1, 1, 1], [1, 1, 1, 1], [5, 1, 1, 1]]
# append the element in the list but the appended element as you can see is appended in last but you want that in starting
a.reverse()
out:[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#So at last reverse the whole list to get the desired list