使用'时出现意外行为;追加';Python列表
我试图理解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
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)