你用错了id()。 id([]) 获取立即丢弃的对象的内存 ID。毕竟,一旦id() 完成了它,就再也没有引用它了。所以下次你使用id([]) Python 看到了重用内存的机会,你瞧,这些地址确实是一样的。
但是,这是一个实现细节,你不能依赖它,而且它并不总是能够重用内存地址。
请注意,id() 值仅在对象的生命周期内是唯一的,请参阅documentation:
这是一个整数,保证在其生命周期内对于该对象是唯一且恒定的。 生命周期不重叠的两个对象可能具有相同的id() 值。
(我的粗体强调)。
id(list()) 无法重用内存位置可能是由于将当前帧压入堆栈以调用函数,然后在list() 调用返回时再次弹出它导致的额外堆突变。
[] 和 list() 都产生一个 new 空列表对象;但您需要首先创建对这些单独列表的引用(此处为 a 和 b):
>>> a, b = [], []
>>> a is b
False
>>> id(a) == id(b)
False
>>> a, b = list(), list()
>>> a is b
False
>>> id(a) == id(b)
False
当您使用[].__repr__ 时也会发生同样的情况。 Python 交互式解释器有一个特殊的全局名称 _,您可以使用它来引用最后生成的结果:
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x10e011608>
>>> _
<method-wrapper '__repr__' of list object at 0x10e011608>
这会创建一个额外的引用,因此 __repr__ 方法,以及您为其创建的空列表,仍然被认为是活动的。内存位置未释放,不可用于您创建的下一个列表。
但是再次执行[].__repr__,Python 现在将_ 绑定到那个新方法对象。突然间,之前的__repr__ 方法不再被任何东西引用并且可以被释放,列表对象也是如此。
第三次执行[].__repr__ 时,第一个内存位置可再次用于重用,因此 Python 就是这样做的:
>>> [].__repr__ # create a new method
<method-wrapper '__repr__' of list object at 0x10e00cb08>
>>> _ # now _ points to the new method
<method-wrapper '__repr__' of list object at 0x10e00cb08>
>>> [].__repr__ # so the old address can be reused
<method-wrapper '__repr__' of list object at 0x10e011608>
您永远不会创建两个以上的列表;前一个(仍由_ 引用)和当前一个。如果您想查看更多内存位置,请使用变量添加另一个引用。