Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 子列表中意外反映的列表更改列表_Python_List_Nested Lists_Mutable - Fatal编程技术网

Python 子列表中意外反映的列表更改列表

Python 子列表中意外反映的列表更改列表,python,list,nested-lists,mutable,Python,List,Nested Lists,Mutable,我需要用Python创建一个列表列表,因此我键入了以下内容: myList = [[1] * 4] * 3 列表如下所示: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] [[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]] 然后我更改了其中一个最里面的值: myList[0][0] = 5 现在,我的列表如下所示: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] [

我需要用Python创建一个列表列表,因此我键入了以下内容:

myList = [[1] * 4] * 3
列表如下所示:

[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]  
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]  
然后我更改了其中一个最里面的值:

myList[0][0] = 5
现在,我的列表如下所示:

[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]  
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]  
这不是我想要或期望的。有人能解释一下发生了什么事,以及如何避开它吗

[[1] * 4] * 3
甚至:

[[1, 1, 1, 1]] * 3
创建一个引用内部
[1,1,1,1]
三次的列表-而不是内部列表的三个副本,因此,无论何时修改列表(在任何位置),都会看到三次更改

与本例相同:

>>> 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]]
>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]

当你写
[x]*3
时,你基本上得到了一个列表
[x,x,x]
。也就是说,对同一
x
有3个引用的列表。然后,当您修改此单个
x
时,它将通过对它的所有三个引用可见:

x = [1] * 4
l = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
    f"id(l[0]): {id(l[0])}\n"
    f"id(l[1]): {id(l[1])}\n"
    f"id(l[2]): {id(l[2])}"
)
# id(l[0]): 140560897920048
# id(l[1]): 140560897920048
# id(l[2]): 140560897920048

x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"l: {l}")
# l: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]
要修复它,您需要确保在每个位置创建一个新列表。一种方法是

[[1]*4 for _ in range(3)]
它将每次重新评估
[1]*4
,而不是评估一次并引用一个列表中的3个


您可能想知道为什么
*
不能像列表理解那样创建独立对象。这是因为乘法运算符
*
对对象进行操作,而看不到表达式。当您使用
*
[[1]*4]
乘以3时,
*
只会看到1元素列表
[[1]*4]
的计算结果,而不是
[[1]*4
表达式文本。
*
不知道如何复制该元素,也不知道如何重新计算
[[1]*4]
,甚至不知道您想要复制,而且通常,甚至可能没有复制元素的方法

*
唯一的选择是对现有子列表进行新的引用,而不是尝试创建新的子列表。其他任何内容都将不一致,或者需要对基本语言设计决策进行重大重新设计

相反,列表理解在每次迭代时都会重新评估元素表达式。
[[1]*4代表范围(3)中的n]
每次都会重新评估
[1]*4
,原因相同
[x**2代表范围(3)]
每次都会重新评估
x**2
*4生成一个新列表,因此列表理解功能可以满足您的需要


顺便说一句,
[1]*4
也不会复制
[1]
的元素,但这并不重要,因为整数是不可变的。你不能像
1.value=2
那样把1变成2。

实际上,这正是你所期望的。让我们来分解一下这里发生的事情:

你写

lst = [[1] * 4] * 3
这相当于:

lst1 = [1]*4
lst = [lst1]*3
这意味着
lst
是一个包含3个元素的列表,所有元素都指向
lst1
。这意味着以下两行是等效的:

lst[0][0] = 5
lst1[0] = 5
As
lst[0]
不过是
lst1

要获得所需的行为,可以使用列表理解:

lst = [ [1]*4 for n in range(3) ] #python 3
lst = [ [1]*4 for n in xrange(3) ] #python 2
在这种情况下,表达式将针对每个n重新求值,从而生成不同的列表

size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for i in range(size)]


让我们用以下方式重写您的代码:

x = 1
y = [x]
z = y * 4

myList = [z] * 3
然后运行下面的代码,让一切变得更加清晰。代码的作用基本上是打印获得的对象的s,这

返回对象的“标识”

并将帮助我们识别它们并分析发生的情况:

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
,和一个包含
x
的单元素列表
y
。你的第一步是
y*4
,它将得到一个新的列表
z
,基本上是
[x,x,x]
,也就是说,它创建了一个新的列表,其中将有4个元素,它们是对初始
x
对象的引用。净步骤非常类似。基本上是
z*3
,即
[[x,x,x,x]]*3
并返回
[[x,x,x,x],[x,x,x]]
,原因与第一步相同。

如果您使用的是python-2.x,请在列表理解范围内,除了正确解释问题的公认答案之外,使用
xrange()
,返回一个更高效的生成器(
range()
,在python 3中也做同样的工作)
\uu
而不是一次性变量
n

[[1]*4 for _ in xrange(3)]      # and in python3 [[1]*4 for _ in range(3)]
此外,作为一种更具python风格的方法,您可以使用它创建重复元素的迭代器对象:

>>> a=list(repeat(1,4))
[1, 1, 1, 1]
>>> a[0]=5
>>> a
[5, 1, 1, 1]
注意:使用numpy,如果您只想创建一个1或0数组,可以使用
np.one
np.zero
和/或其他数字使用
np.repeat()


Python容器包含对其他对象的引用。请参见此示例:

>>> 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]]
>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]
在此
b
中,是一个列表,其中包含一个项目,该项目是对列表
a
的引用。列表
a
是可变的

一个列表乘以一个整数相当于将该列表自身多次相加(请参阅)。因此,继续下面的示例:

>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]
我们可以看到列表
c
现在包含对列表
a
的两个引用,这相当于
c=b*2


Python常见问题解答还包含对这种行为的解释:

我想每个人都会解释发生了什么。 我建议一种解决方法:

myList=[[1表示范围(4)中的i]表示范围(3)中的j]

打印myList

然后你有:

[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

简单地说,这是因为在python中,一切都是通过引用来工作的,所以当您以这种方式创建列表时,基本上会遇到这样的问题

要解决您的问题,您可以执行以下任一操作: 1.使用numpy数组 2.将列表添加到列表中。
3.如果需要,也可以使用内置列表功能使用字典
y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [1, 0]]
import copy
y = [0] * 2   
print(y)   # [0, 0]

y = [y, copy.deepcopy(y)]  
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [0, 0]]
import copy
y = [0] * 2
print(y) # [0, 0]

y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]

y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]
myList = [[1]*4 for _ in range(3)]
myList = [[1 for __ in range(4)] for _ in range(3)]
>>> 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
    arr = [[0]*cols]*row
   rows, cols = (5, 5) 
   arr = [[0 for i in range(cols)] for j in range(rows)] 

   arr = [0]*N 
   arr = [0 for i in range(N)] 
>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]
>>> A
[[None, None], [None, None], [None, None]]
>>> A[0][0] = 5
>>> A
[[5, None], [5, None], [5, None]]
node_count = 4
colors = [0,1,2,3]
sol_dict = {node:colors for node in range(0,node_count)}
>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> [v is colors for v in sol_dict.values()]
[True, True, True, True]
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 2, 3], 2: [0, 2, 3], 3: [0, 2, 3]}
>>> colors = [0,1,2,3]
>>> sol_dict = {node:colors[:] for node in range(0,node_count)}
>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}