使用'时出现意外行为;追加';Python列表

使用'时出现意外行为;追加';Python列表,python,list,Python,List,我试图理解python列表的这种行为 当我将一个空列表附加到另一个列表时,我希望新列表只包含一个空列表。但我不明白为什么它会增加意想不到的价值 main = [ [1,2,3], [4,5], [6] ] l1 = [] l2 = [] for i in main: for j in i: l1.append(j) # reseting value of l1 to empty list l1 = [] # exp

我试图理解python列表的这种行为

当我将一个空列表附加到另一个列表时,我希望新列表只包含一个空列表。但我不明白为什么它会增加意想不到的价值

main = [ [1,2,3], [4,5], [6] ]

l1 = []
l2 = []

for i in main:
    
    for j in i:
        l1.append(j)
    
    # reseting value of l1 to empty list
    l1 = []
    
    # expected behaviour: an empty list will be added!
    l2.append(l1)

print(l2)
我希望打印此代码

> [[], [], []]
但这是给我的

> [[4, 5], [6], []]

有人能解释一下这是怎么发生的吗?

python列表是可变的,append方法会“就地”更改它们。 赋值实际上使变量指向内存中的另一个位置。在第一次从最里面的循环退出后,您将l1重置为指向空列表,以便
l2设置为[[]]
。接下来,在内部循环中,修改该空列表。下一步
l1=[]
创建一个空列表并将“l1”指向它。这个过程重复。 您可以在循环
print(l2)
中添加调试语句,然后查看您自己

由于处理可变数据和不可变数据的复杂性,这一趋势越来越明显。对于像tuple这样的不可变类型,您将不会遇到此类问题

虽然列表有时令人困惑,但在许多情况下,列表比元组更方便,但要特别小心使用它们。例如,我建议做更多的列表练习,以便更好地理解它可能导致的后果


另一个具有可变数据的python gotcha是可以在函数内部修改的默认函数参数值。

它将附加到列表中,而不是清除。请尝试以下操作:

l1.clear()
而不是

l1 = []

l1=[]
并不意味着“清除此列表”。这意味着“创建一个新的空列表,并使
l1
名称引用该列表”。前面提到的任何对象
l1
都不会被此操作修改

另外,
l2.append(l1)
并不意味着“将
l1
的副本追加到
l2
”或“将此变量追加到
l2
”。它的意思是“将此特定列表附加到
l2
l2
接收对原始列表的引用,而不是新列表,对原始列表的修改将通过
l2
可见。(它接收对列表的引用,而不是对
l1
变量的引用-将
l1
重新绑定到新列表不会影响
l2


在外部循环的第一次迭代结束时,将一个空列表附加到
l2
。然后,下一次迭代将一组内容追加到该列表中,然后将
l1
重新绑定到一个新的空列表中,在旧列表中留下一组元素。在外循环的下一次也是最后一次迭代中也会发生同样的情况

如果要清除列表,请使用

l1.clear()

而不是
l1=[]

此外,如果要创建列表的(浅)副本,可以使用
l1[:]
。例如,将
l1
的副本附加到
l2

l2.append(l1[:])`

如果将代码更改为清除
l1
,但不将副本附加到
l2
,则
l2
将包含对单个列表的3个引用。这很少是您想要的。

您的
l2
列表将在下一次迭代中更改。也许这段代码会给你更多的解释:

for i in main:

    for j in i:
        l1.append(j)
    print(id(l1),id(l2))
    if l2:
        print(id(l2[0]))
    # reseting value of l1 to empty list
    l1 = []

    # expected behaviour: an empty list will be added!
    l2.append(l1)

检查
l2[0]
l1
ID是否相等。

在外部循环的第一次迭代中,附加一个空列表
li
。然后在下一次迭代中,您的内部循环将一组值附加到该列表中。因此考虑<代码> a= [];b=[];a、 附加(b);b、 追加(42);打印(a)
for i in main:

    for j in i:
        l1.append(j)
    print(id(l1),id(l2))
    if l2:
        print(id(l2[0]))
    # reseting value of l1 to empty list
    l1 = []

    # expected behaviour: an empty list will be added!
    l2.append(l1)