Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.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创建一个列表列表,因此我键入了以下内容: my_list = [[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]] 然后我更改了其中一个最里面的值: my_list[0][0] = 5 现在,我的列表如下所示: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

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

my_list = [[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]]  
然后我更改了其中一个最里面的值:

my_list[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) ]
在这种情况下,将针对每个
n
重新计算表达式,从而生成不同的列表

size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for _ in range(size)]
使用Python教程:


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

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

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

返回对象的“标识”

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

print("my_list:")
for i, sub_list in enumerate(my_list):
    print("\t[{}]: {}".format(i, id(sub_list)))
    for j, elem in enumerate(sub_list):
        print("\t\t[{}]: {}".format(j, id(elem)))
您将获得以下输出:

x: 1
y: [1]
z: [1, 1, 1, 1]
my_list:
    [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]]
,原因与第一步相同。

与正确解释问题的公认答案一起,而不是使用以下代码创建包含重复元素的列表:

[[1]*4 for _ in range(3)]
此外,还可以使用创建重复元素的迭代器对象:

>>> a = list(repeat(1,4))
[1, 1, 1, 1]
>>> a[0] = 5
>>> a
[5, 1, 1, 1]
注意:如果您使用的是NumPy,并且您只想创建一个1或0数组,您可以使用和/或其他数字使用:


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常见问题解答还包含对此行为的解释:

每个人都在解释正在发生的事情。我将建议一种解决方法:

my_list = [[1 for i in range(4)] for j in range(3)]

my_list[0][0] = 5
print(my_list)
然后你会得到:

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

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

要解决您的问题,您可以执行以下任一操作: 1.使用numpy数组 2.将列表添加到列表中。
3.如果需要,您也可以使用dictionary,通过使用内置列表功能,您可以这样做

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

试图用更具描述性的方式解释它

行动1:

x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]

x[0][0] = 1
print(x) # [[1, 0], [0, 0]]
另一种创建克隆拷贝的有趣方法是操作4:

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]]

my_list=[[1]*4]*3
在内存中创建一个列表对象
[1,1,1]
,并将其引用复制3次。这相当于
obj=[1,1,1]
my_list = [[1 for __ in range(4)] for _ in range(3)]
>>> my_list = [1]*4
>>> my_list
[1, 1, 1, 1]

>>> id(my_list[0])
4522139440
>>> id(my_list[1])  # Same as my_list[0]
4522139440
>>> my_list[1] = 42  # Since my_list[1] is immutable, this operation overwrites my_list[1] with a new object changing its id.
>>> my_list
[1, 42, 1, 1]

>>> id(my_list[0])
4522139440
>>> id(my_list[1])  # id changed
4522140752
>>> id(my_list[2])  # id still same as my_list[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]}