为什么Python中的id({})== id({})和id([])== id([])?

时间:2010-10-06 22:00:39

标签: python identity cpython python-internals

为什么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([]))

我有一些想法为什么可能,但无法找到具体的原因。

修改

进一步证明格伦和托马斯的观点:

[1] id([])
4330909912
[2] x = []
[3] id(x)
4330909912
[4] id([])
4334243440

4 个答案:

答案 0 :(得分:41)

当你调用id({})时,Python会创建一个dict并将其传递给id函数。 id函数获取其id(其内存位置),并丢弃该dict。这个词被摧毁了。当您快速连续两次执行时(同时没有创建任何其他dicts),dict Python第二次创建时会使用与第一次相同的内存块。 (CPython的内存分配器比它听起来更有可能。)因为(在CPython中)id使用内存位置作为对象id,所以两个对象的id是相同的。如果你将dict分配给变量然后得到它id(),这显然不会发生,因为dicts同时存在 ,所以他们的id必须与众不同。

可变性并没有直接起作用,而是缓存元组和字符串的代码对象。在相同的代码对象(函数或类主体或模块主体)中,将重用相同的文字(整数,字符串和某些元组)。可变对象永远不能重复使用,它们总是在运行时创建。

简而言之,对象的id在对象的生命周期中只是唯一的 。在对象被销毁之后,或者在创建对象之前,其他东西可以具有相同的id。

答案 1 :(得分:34)

CPython一旦超出范围就会垃圾收集对象,因此在收集第一个[]后创建第二个[]。因此,大部分时间它都在同一个内存位置。

这显示了非常清楚的事情(在其他Python实现中输出可能会有所不同):

class A(object):
    def __init__(self): print "a",
    def __del__(self): print "b",

# a a b b False
print A() is A()
# a b a b True
print id(A()) == id(A())

答案 2 :(得分:-1)

它在Jython中的工作方式不同......

>>> id({})
1
>>> id([])
2

是否可以对常用(即空)容器进行“实施”以节省分配成本?

这(在CPython中)建议不要:

>>> def mutateid(obj):
...   obj.append('x')
...   print obj
...   print id(obj)
... 
>>> mutateid([])
['x']
4299590472
>>> id([])
4299590472
>>> 

答案 3 :(得分:-4)

列表和dicts上的==运算符不会比较对象ID以查看它们是否是同一个对象 - 请使用obj1 is obj2

而是==运算符比较dict列表的成员以查看它们是否相同。