【问题标题】:Is there a difference between [] and list() when using id()?使用 id() 时 [] 和 list() 有区别吗?
【发布时间】:2016-11-26 17:01:09
【问题描述】:

有人能解释一下吗?

为什么id一样,list不一样?

>>> [] is []
False
>>> id([]) == id([])
True

列表创建有区别吗?

>>> id(list()) == id(list())
False
>>> id([]) == id([])
True

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

>>> [].__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>

【问题讨论】:

    标签: python list python-internals


    【解决方案1】:

    你用错了id()id([]) 获取立即丢弃的对象的内存 ID。毕竟,一旦id() 完成了它,就再也没有引用它了。所以下次你使用id([]) Python 看到了重用内存的机会,你瞧,这些地址确实是一样的。

    但是,这是一个实现细节,你不能依赖它,而且它并不总是能够重用内存地址。

    请注意,id() 值仅在对象的生命周期内是唯一的,请参阅documentation

    这是一个整数,保证在其生命周期内对于该对象是唯一且恒定的。 生命周期不重叠的两个对象可能具有相同的id() 值。

    (我的粗体强调)。

    id(list()) 无法重用内存位置可能是由于将当前帧压入堆栈以调用函数,然后在list() 调用返回时再次弹出它导致的额外堆突变。

    []list() 都产生一个 new 空列表对象;但您需要首先创建对这些单独列表的引用(此处为 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
    

    当您使用[].__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>
    

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

    【讨论】:

      猜你喜欢
      • 2011-05-20
      • 2017-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-19
      相关资源
      最近更新 更多