【发布时间】:2011-04-22 02:11:21
【问题描述】:
为什么 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
【问题讨论】:
-
哇,这很奇怪。看起来如果你得到一个新的 dict/list 的 id,然后让它的引用计数下降到零,然后得到另一个新的 dict/list,它将具有相同的 id。当其引用计数降至零时,它看起来像一个未修改的字典/列表被保存以备后用。我的猜测是,这是针对创建并立即丢弃字典/列表的代码的情况的优化。这很常见,例如:使用
setdefault的代码经常这样做。 -
@Potatoswatter:绝对不是。对象的ID在创建后永远不会改变,而list和dicts是可变对象,所以空lists和dicts不能像字符串和小数字那样被记忆。
-
@Glenn Maynard:从技术上讲,您可以通过在丢弃之前先清空它们来记忆空列表和字典;但是,与创建新处理器相比,这可能只是浪费处理器周期。
-
@Lie Ryan:我真的不知道你在说什么,但你不能记住空列表,因为对象的 id 必须在其生命周期内保持不变。
-
@Glenn Maynard:是的,你可以。从技术上讲,您可以拥有一个空列表和空字典池;每次你需要一个新的字典时,都会检查这个池,每次你处理一个列表时(即当引用计数为零时)你把列表/字典放回池中。不要求两个不同时间的两个对象不具有相同的 id()。但是,这里没有太多的节省。 我刚刚意识到,这不是记忆,而是缓存
标签: python identity cpython python-internals