Python会尽可能重用列表吗?

4 投票
5 回答
1384 浏览
提问于 2025-04-17 20:50

我的意思是,如果你用一个形状相同的列表去覆盖一个列表,它会保留第一个列表吗?比如:

point = [1, 2]
for x in xrange(10000000):
    point = [x, x + 1]

在每次循环中,Python会重新使用point = [1, 2]这个列表,只是把point[0]point[1]的值更新为xx + 1吗?还是说每次循环都会创建一个新列表,然后把旧的丢掉?换句话说,这样做的性能和

point = [1, 2]
for x in xrange(10000000):
    point[0] = x
    point[1] = x + 1

我只是好奇Python在背后是否会进行这种优化。

编辑:除了大家下面说的,我也出于好奇做了一些基准测试。

在我那台老旧的ThinkPad Core2Duo上:

point = [1, 2]
for x in xrange(10000000):
    point = [x, x + 1]

# Result:
# real    0m6.164s


point = [1, 2]
for x in xrange(10000000):
    point[0] = x
    point[1] = x + 1

# Result:
# real    0m3.623s

5 个回答

2

这一行 point = [x, x + 1] 主要做了两件事:

  1. [x, x + 1] 创建了一个新的列表。在这个时候,Python 并不知道你会用这个列表 point 来做什么,或者你接下来会怎么处理它。
  2. point = ... 将新创建的列表赋值给之前的列表,同时释放掉之前的列表。
2

不,Python在写 point = [x,x+1] 时不会重复使用列表。顺便说一下,你可以进行就地赋值,这样列表就会保持不变。

举个例子:

point = [1,2]

for x in range(5): # Reusing point list
    point[:] = [x,x+1]

for x in range(5): # Creating new list
    point = [x,x+1]

正如@wim所说,你可以用 id(point) 来检查内存地址。

3

不,情况并不是这样。当你写 point = [1, 2] 的时候,实际上是Python创建了一个列表 [1, 2],然后让 point 指向这个列表在内存中的地址。接着,当你写 point = [x, x+1] 时,Python又创建了一个全新的列表,并且简单地把 point 指向这个新列表的内存地址。原来的列表 [1, 2] 其实还是在内存里的,只是你无法再访问它,之后Python会自动把它清理掉。

你可以这样做:

point = [1, 2]
b = point
point = [3, 4]
print(b == point)

point2= [1, 2]
c = point2
point2[0] = 3
print(c == point2)

这个输出能说明一切。

4

加上这个 print 来找出你的答案:

point = [1, 2]
for x in xrange(10000000):
    point = [x, x + 1]
    print(id(point))

这样做可以告诉你 point 的内存位置,从而判断它是否在重复使用这个实例,或者让它被垃圾回收。

7

不,CPython 不会重用列表对象。那行代码 point = [x, x + 1] 会创建一个全新的对象,如果 point 是唯一指向之前那个对象的引用,那么之前的对象就会被销毁。

不过,Python 确实会重用 tuple 对象(有个上限),因为在正常运行 Python 程序时,Python 内部会创建和销毁很多元组。想了解更多,可以查看 元组在 CPython 中是如何实现的?

撰写回答