我需要在Python中创建列表列表,因此输入了以下内容:
myList = [[1] * 4] * 3
该列表如下所示:
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
然后,我更改了最内在的值之一:
myList[0][0] = 5
现在我的列表如下所示:
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
这不是我想要或期望的。有人可以解释发生了什么,以及如何解决吗?
我需要在Python中创建列表列表,因此输入了以下内容:
myList = [[1] * 4] * 3
该列表如下所示:
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
然后,我更改了最内在的值之一:
myList[0][0] = 5
现在我的列表如下所示:
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
这不是我想要或期望的。有人可以解释发生了什么,以及如何解决吗?
通过使用内置列表功能,您可以像这样
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
让我们以以下方式重写您的代码:
x = 1
y = [x]
z = y * 4
myList = [z] * 3
然后,运行以下代码使所有内容更加清晰。该代码所做的基本上是打印id
获得的对象的,
返回对象的“身份”
并将帮助我们识别它们并分析发生的情况:
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)))
您将获得以下输出:
x: 1
y: [1]
z: [1, 1, 1, 1]
myList:
[0]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
[1]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
[2]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
现在让我们逐步进行。你有x
哪些是1
和一个单一的元素列表y
包含x
。第一步是y * 4
将获得一个z
基本上是的新列表,[x, x, x, x]
即创建一个包含4个元素的新列表,这些元素是对初始x
对象的引用。净步骤非常相似。基本上z * 3
,您要做的是[[x, x, x, x]] * 3
和返回[[x, x, x, x], [x, x, x, x], [x, x, x, x]]
,其原因与第一步相同。
@spelchekr来自Python的列表乘法:[[...]] * 3使得3个列表在修改后会相互镜像,我也有一个相同的问题:“为什么只有外部* 3创建更多引用,而内部* 3却没有创建更多引用为什么不是全1?”
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]]
尝试上面的代码后,这是我的解释:
*3
也创建引用,但是它的引用是不可变的,类似[&0, &0, &0]
,然后在进行更改时li[0]
,您无法更改const int的任何基础引用0
,因此您只需将引用地址更改为新的引用地址即可&1
;ma=[&li, &li, &li]
和li
mutable是可变的,因此当您调用时ma[0][0]=1
,ma [0] [0]等于to &li[0]
,因此所有&li
实例都将其第一个地址更改为&1
。我想每个人都解释发生了什么。我建议一种解决方法:
myList = [[1 for i in range(4)] for j in range(3)]
myList[0][0] = 5
print myList
然后您有:
[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
Python容器包含对其他对象的引用。请参阅以下示例:
>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]
在此b
列表中包含一个项目,该项目是对list的引用a
。该列表a
是可变的。
将列表乘以整数等于将列表多次添加到自身(请参阅常见序列操作)。因此,继续下面的示例:
>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]
我们可以看到列表c
现在包含两个对list的引用,a
它们等效于c = b * 2
。
Python FAQ也包含此行为的解释:如何创建多维列表?
实际上,这正是您所期望的。让我们分解一下这里发生的事情:
你写
lst = [[1] * 4] * 3
这等效于:
lst1 = [1]*4
lst = [lst1]*3
这意味着lst
一个包含3个元素的列表lst1
。这意味着以下两行是等效的:
lst[0][0] = 5
lst1[0] = 5
至于lst[0]
是什么,但lst1
。
要获得所需的行为,可以使用列表理解:
lst = [ [1]*4 for n in range(3) ] #python 3
lst = [ [1]*4 for n in xrange(3) ] #python 2
在这种情况下,将对每个n重新计算表达式,从而得出不同的列表。
简而言之,这是因为在python中,所有内容都可以通过引用来工作,因此,当您以这种方式创建列表列表时,基本上会遇到此类问题。
要解决您的问题,您可以执行以下任一操作:1.将numpy数组文档用于numpy.empty。2 .将列表追加到列表中。3.您也可以使用字典
除了可以正确解释问题的公认答案之外,在列表理解范围内,如果您使用的是python-2.x,则使用return会xrange()
生成一个更有效的生成器(range()
在python 3中执行相同的工作),_
而不是throwaway变量n
:
[[1]*4 for _ in xrange(3)] # and in python3 [[1]*4 for _ in range(3)]
另外,作为一种Python方式,您可以itertools.repeat()
用来创建重复元素的迭代器对象:
>>> a=list(repeat(1,4))
[1, 1, 1, 1]
>>> a[0]=5
>>> a
[5, 1, 1, 1]
PS使用numpy的,如果你只是想创建1或0,你可以使用数组np.ones
和np.zeros
和/或其他使用次数np.repeat()
:
In [1]: import numpy as np
In [2]:
In [2]: np.ones(4)
Out[2]: array([ 1., 1., 1., 1.])
In [3]: np.ones((4, 2))
Out[3]:
array([[ 1., 1.],
[ 1., 1.],
[ 1., 1.],
[ 1., 1.]])
In [4]: np.zeros((4, 2))
Out[4]:
array([[ 0., 0.],
[ 0., 0.],
[ 0., 0.],
[ 0., 0.]])
In [5]: np.repeat([7], 10)
Out[5]: array([7, 7, 7, 7, 7, 7, 7, 7, 7, 7])
[[1] * 4] * 3
甚至:
[[1, 1, 1, 1]] * 3
创建一个引用内部[1,1,1,1]
3次的列表-而不是内部列表的3个副本,因此,每次修改列表(在任何位置)时,都会看到3次更改。
与此示例相同:
>>> inner = [1,1,1,1]
>>> outer = [inner]*3
>>> outer
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
>>> inner[0] = 5
>>> outer
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
可能不那么令人惊讶。
size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for i in range(size)]
myList = [[1]*4] * 3
[1,1,1,1]
在内存中创建一个列表对象,然后将其引用复制3次。这等效于obj = [1,1,1,1]; myList = [obj]*3
。列表中引用的obj
任何地方,对的任何修改都会在三个地方反映出来obj
。正确的声明是:要么
这里要注意的重要一点是,
*
运算符通常用于创建文字列表。虽然1
是一成不变的,obj =[1]*4
但仍将创建1
重复4遍以上的列表[1,1,1,1]
。但是,如果对不可变对象进行了任何引用,则该对象将被新对象覆盖。这意味着,如果我们这样做
obj[1]=42
,那么obj
它将变得[1,42,1,1]
不像某些人想象的那样。这也可以验证:[42,42,42,42]