为什么CPython中的id({})== id({})和id()== id()?
为什么CPython(不知道其他Python实现)具有以下行为?
tuple1 = () tuple2 = () dict1 = {} dict2 = {} list1 = [] list2 = [] # makes sense, tuples are immutable assert(id(tuple1) == id(tuple2)) # also makes sense dicts are mutable assert(id(dict1) != id(dict2)) # lists are mutable too assert(id(list1) != id(list2)) assert(id(()) == id(())) # why no assertion error on this? assert(id({}) == id({})) # or this? assert(id([]) == id([]))
我有一些想法,为什么可以 ,但是找不到具体的原因。
编辑
为了进一步certificate格伦和托马斯的观点:
[1] id([]) 4330909912 [2] x = [] [3] id(x) 4330909912 [4] id([]) 4334243440
CPython在垃圾收集对象超出范围后立即收集对象,因此在收集第一个[]
之后创build第二个[]
。 所以,大部分时间都是在同一个内存位置。
这显示了非常清楚的事情(Python的其他实现可能会有所不同):
class A(object): def __init__(self): print "a", def __del__(self): print "b", # aabb False print A() is A() # abab True print id(A()) == id(A())
当你调用id({})
,Python会创build一个字典并将其传递给id
函数。 id
函数将其id(它的内存位置),并丢弃字典。 字典被破坏。 当你连续执行两次(同时没有创build任何其他的字典)时,字典Python创build的第二次恰好是第一次使用相同的内存块。 (CPython的内存分配器比听起来更有可能)。由于(在CPython中) id
使用内存位置作为对象id,所以两个对象的id是相同的。 这显然不会发生,如果您将字典赋予一个variables,然后得到它的id()
,因为字典是同时存在 ,所以他们的id
必须是不同的。
可变性不直接发挥作用,但caching元组和string的代码对象可以做到。 在相同的代码对象(函数或类的主体或模块体)相同的文字(整数,string和某些元组)将被重用。 可变对象永远不能被重用,它们总是在运行时创build的。
简而言之,一个对象的id只在对象的生命周期中是唯一的 。 在对象被销毁之后,或者在被创build之前,别的东西可以拥有相同的id。
它在Jython中的工作方式不同
>>> id({}) 1 >>> id([]) 2
在那里通常使用(即空的)集装箱被“实习”以节省分配成本的情况下是否可以进行优化?
这(在CPython中)不build议:
>>> def mutateid(obj): ... obj.append('x') ... print obj ... print id(obj) ... >>> mutateid([]) ['x'] 4299590472 >>> id([]) 4299590472 >>>
列表和字典上的==运算符不会比较对象ID,看看它们是否是同一个对象 – 使用obj1 is obj2
。
相反,==运算符比较字典列表的成员,看它们是否相同。