【问题标题】:Untie nested lists created by repetition? [duplicate]解开重复创建的嵌套列表? [复制]
【发布时间】:2018-03-20 04:15:49
【问题描述】:

我想通过重复一个简单列表来创建一个嵌套列表,比如说

x = ['a','b','c']
y = [x] * 3

这会导致

[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]

当我更改嵌套列表之一的元素时,所有其他列表中的相应元素也会更改:

y[0][0] = 'z'

[['z', 'b', 'c'], ['z', 'b', 'c'], ['z', 'b', 'c']]

我应该怎么做才能获得以下列表而不是所有列表项中的上述更改?

[['z', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]

【问题讨论】:

标签: python python-3.x list


【解决方案1】:

列表是python中的引用。因此,您正在使用您的代码按原样制作对 x 列表的 3 个引用的列表。有几种方法可以解决这个问题,并制作列表的真实副本,切片就是其中之一。 Slice 将根据切片范围从主列表中返回一个新列表。

下面我简单地使用循环来循环你想要的次数 (3) 并每次切 x 列表的整个范围,所以我返回它的副本。然后我只是将结果切片附加到 y 列表中。

也许不是最漂亮的,但解决了这个问题。

x = ['a','b','c']
y = []
for n in range(3):
    y.append(x[:])

print(y)

y[0][0] = 'z'

print(y)

输出:

[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
[['z', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]

【讨论】:

  • 我也像这样重写了你的答案:y = [x[:] for _ in range(3)]
【解决方案2】:

让我们从头开始,深入探索一下:

所以假设你有两个列表:

list_1=['01','98']
list_2=[['01','98']]

我们必须复制两个列表,现在从第一个列表开始:

那么首先,让我们尝试一下一般的复制方法:

copy=list_1

现在,如果您认为复制了 list_1,那么您可能是错的,让我们检查一下:

The id() function shows us that both variables point to the same list object, i.e. they share this object.
print(id(copy))
print(id(list_1))

输出:

4329485320
4329485320

惊讶吗?好的,让我们来探索一下:

所以我们知道python不会在变量中存储任何东西,变量只是引用对象,对象存储值。这里的对象是list,但是我们用两个不同的变量名创建了对同一个对象的两个引用。所以两个变量都指向同一个对象:

所以当您执行copy=list_1 时,它实际上在做什么:

在图像中,list_1 和副本是两个变量名,但两个变量的对象相同,即 list

因此,如果您尝试修改复制的列表,那么它也会修改原始列表,因为该列表只有一个,无论您是从复制的列表还是从原始列表进行修改,您都将修改该列表:

copy[0]="modify"

print(copy)
print(list_1)

输出:

['modify', '98']
['modify', '98']

所以它修改了原来的列表:

那么解决办法是什么?

解决方案:

现在让我们转向第二种复制列表的pythonic方法:

copy_1=list_1[:]

现在这个方法解决了我们在第一个问题中遇到的问题,让我们检查一下:

print(id(copy_1))
print(id(list_1))

4338792136
4338791432

所以我们可以看到我们的两个列表都有不同的 id,这意味着两个变量都指向不同的对象,所以这里实际发生的是:

现在让我们尝试修改列表,看看我们是否仍然面临之前的问题:

copy_1[0]="modify"

print(list_1)
print(copy_1)

输出:

['01', '98']
['modify', '98']

所以你可以看到它没有修改原始列表,它只是修改了复制的列表,所以我们可以接受。

所以现在我想我们已经完成了?等等,我们也必须复制第二个嵌套列表,所以让我们尝试一下 pythonic 方式:

copy_2=list_2[:]

所以 list_2 应该引用另一个作为 list_2 副本的对象让我们检查一下:

print(id((list_2)),id(copy_2))

我们得到输出:

4330403592 4330403528

现在我们可以假设两个列表都指向不同的对象,所以现在让我们尝试修改它,看看它是否给出了我们想要的:

所以当我们尝试时:

copy_2[0][1]="modify"

print(list_2,copy_2)

它给了我们输出:

[['01', 'modify']] [['01', 'modify']]

现在,这有点令人困惑,我们使用了 pythonic 方式,但我们仍然面临同样的问题。

让我们理解它:

所以当我们这样做时:

copy_2=list_2[:]

我们实际上只复制了外部列表,而不是嵌套列表,所以嵌套列表对于两个列表来说是同一个对象,让我们检查一下:

print(id(copy_2[0]))
print(id(list_2[0]))

输出:

4329485832
4329485832

所以实际上当我们执行copy_2=list_2[:] 时会发生这种情况:

它创建列表的副本,但只创建外部列表副本,而不是嵌套列表副本,嵌套列表对于两个变量都是相同的,因此如果您尝试修改嵌套列表,那么它也会修改原始列表,因为嵌套列表对象是两个嵌套列表相同。

那么解决办法是什么?

解决方案是deep copy

from copy import deepcopy
deep=deepcopy(list_2)

所以现在让我们检查一下:

print(id((list_2)),id(deep))

输出:

4322146056 4322148040

两个id都不一样,现在我们来看看嵌套列表id:

print(id(deep[0]))
print(id(list_2[0]))

输出:

4322145992
4322145800

如您所见,两个 id 不同,因此我们可以假设两个嵌套列表现在都指向不同的对象。

所以当您执行deep=deepcopy(list_2) 时,实际会发生什么:

所以两个嵌套列表都指向不同的对象,并且它们现在有单独的嵌套列表副本。

现在让我们尝试修改嵌套列表,看看它是否解决了之前的问题:

如果我们这样做:

deep[0][1]="modify"
print(list_2,deep)

输出:

[['01', '98']] [['01', 'modify']]

所以,如您所见,它没有修改原始嵌套列表,它只修改了复制的列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    • 1970-01-01
    • 2019-02-21
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多