为什么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

相反,==运算符比较字典列表的成员,看它们是否相同。