Python 中 list() 的内存管理

8 投票
3 回答
2420 浏览
提问于 2025-04-16 16:06

我正在创建一个元组,然后用下面的代码把它转换成一个列表:

y=("hello","the","world")
y=list(y)

那么,Python是简单地把这些对象标记为现在可以改变,并通过标签y来访问,还是说它会把每个对象都完整复制一遍,放到新的列表结构里,然后再删除原来的不可改变的对象呢?

谢谢!

3 个回答

3

Python 默认情况下不会进行深拷贝,除非你特别要求它这样做。所以结果会是一个新的可变列表,这个列表里包含的都是和你放在元组里的一模一样的对象的引用。

需要注意的是,元组里的对象本身一直都是可变的。只有这个字符串的元组是不可变的,也就是说你不能往元组里添加或删除对象,但你可以随时访问和修改元组里面的对象。

10

你可以通过查看每个对象的 id 来了解它们的情况。

这是我运行的结果。

y=("hello","the","world")
id(y), [id(i) for i in y]
(18627040, [21912480, 21964056, 21910304])

y = list(y)
id(y), [id(i) for i in y]
(21905536, [21912480, 21964056, 21910304])

正如你所看到的,这些对象是相同的。

更新: Sven Marnach 很好地解释了 这是怎么回事以及为什么。作为参考,我对其他类型的对象做了更多测试。

对于一个对象

class C: pass
x = (C(), C(), C())
id(x), [id(i) for i in x]
(18626400, [19992128, 19992008, 19991328])
x= list(x)
id(x), [id(i) for i in x]
(21863560, [19992128, 19992008, 19991328])

对于一个列表

z = ([], [], [])
id(z), [id(i) for i in z]
(18627040, [21908016, 21907136, 21908536])
z = list(z)
id(z), [id(i) for i in z]
(18614992, [21908016, 21907136, 21908536])

对于一个列表的列表

p = ([[], []], [[], []], [[], []])
id(p), [[id(i) for i in j] for j in p]
(18627040, [[21919504, 21895808], 
            [21894608, 21895008], 
            [19991008, 19789104]])
p = list(p)
id(p), [[id(i) for i in j] for j in p]
(19800352, [[21919504, 21895808], 
            [21894608, 21895008], 
            [19991008, 19789104]])
15

在执行以下这行代码时:

y = list(y)

会发生以下事情:

  1. 右边的内容会被计算。这一步会创建一个新的列表对象。这个列表对象会用传给它的元组里的内容来填充。这里的内容并不是被复制,而是它们的引用计数增加了,也就是说新的列表对象里会保存这些内容的引用。

  2. 新创建的列表对象会被赋值给左边的名字(y)。这一步首先会解除之前y指向的对象的引用,这样就会减少那个元组对象的引用计数。如果这个元组对象的引用计数变成了0,就会被删除。最后,y会指向新的列表对象。

撰写回答