使用id()时,[]和list()之间有区别吗?

Vla*_*nko 38 python list python-internals

有人可以解释以下内容吗?

为什么id相同,但列表不同?

>>> [] is []
False
>>> id([]) == id([])
True
Run Code Online (Sandbox Code Playgroud)

列表创建有区别吗?

>>> id(list()) == id(list())
False
>>> id([]) == id([])
True
Run Code Online (Sandbox Code Playgroud)

为什么会这样?我得到两个不同的列表.为什么不只有一个,三个或更多?

>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868128>
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868170>
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868128>
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868170>
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 75

id()错了.id([])获取立即丢弃的对象的内存id .毕竟,一旦id()完成它就没有任何东西可以引用它了.因此,下次使用id([])Python时会看到重新使用内存的机会,并且看到这些地址确实是相同的.

但是,这是一个实现细节,您不能依赖它,并且它不会始终能够重用内存地址.

请注意,id()值仅对于对象的生命周期是唯一,请参阅文档:

这是一个整数,在该生命周期内保证该对象是唯一且恒定的.具有非重叠寿命的两个对象可以具有相同的id()值.

(大胆强调我的).

id(list())不能重新使用的内存位置可能是由于造成推堆栈上的当前帧调用一个函数,然后再弹出时,它额外的堆突变list()调用返回.

双方[]list()产生一个新的空列表对象; 但您需要首先创建对这些单独列表的引用(此处ab):

>>> a, b = [], []
>>> a is b
False
>>> id(a) == id(b)
False
>>> a, b = list(), list()
>>> a is b
False
>>> id(a) == id(b)
False
Run Code Online (Sandbox Code Playgroud)

使用时会发生同样的情况[].__repr__.Python交互式解释器有一个特殊的全局名称,_您可以使用它来引用最后生成的结果:

>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x10e011608>
>>> _
<method-wrapper '__repr__' of list object at 0x10e011608>
Run Code Online (Sandbox Code Playgroud)

这会创建一个额外的引用,因此该__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>
Run Code Online (Sandbox Code Playgroud)

你永远不会创建两个以上的列表; 前一个(仍由引用_)和当前的一个.如果要查看更多内存位置,请使用变量添加另一个引用.