Python 奇怪的行为与明显的“缓存”有关;{};

Python 奇怪的行为与明显的“缓存”有关;{};,python,Python,今天我了解到Python缓存表达式{},并在将其分配给变量时用新的空dict替换它: print id({}) # 40357936 print id({}) # 40357936 x = {} print id(x) # 40357936 print id({}) # 40356432 我没有看过源代码,但我有一个想法,这可能是如何实现的。(可能当全局{}的引用计数增加时,全局{}被替换。) 但请考虑一下: def f(x): x['a'] = 1 print(id(x

今天我了解到Python缓存表达式
{}
,并在将其分配给变量时用新的空dict替换它:

print id({})
# 40357936

print id({})
# 40357936

x = {}
print id(x)
# 40357936

print id({})
# 40356432
我没有看过源代码,但我有一个想法,这可能是如何实现的。(可能当全局
{}
的引用计数增加时,全局
{}
被替换。)

但请考虑一下:

def f(x):
    x['a'] = 1
    print(id(x), x)

print(id(x))
# 34076544

f({})
# (34076544, {'a': 1})

print(id({}), {})
# (34076544, {})

print(id({}))
# 34076544
f
修改全局dict而不导致其被替换,并打印出修改后的dict。但是在
f
之外,尽管id相同,全局dict现在为空

发生了什么事???

它没有被缓存——如果你没有将
{}
的结果分配到任何地方,它的引用计数是0,它会被立即清除。碰巧您分配的下一个内存重用了旧内存。当您将其分配给
x
时,您将使其保持活动状态,然后下一个将具有不同的地址


在函数示例中,一旦
f
返回,就没有对dict的剩余引用,因此它也会被清除,同样的事情也会发生。

Python在这里不做任何缓存。当
id()
在程序中的不同点给出相同的返回值时,有两种可能性:

  • 对同一对象调用了两次
    id()
  • 在创建第二个对象之前,对调用了
    id()
    的第一个对象进行了垃圾收集,并在与原始对象相同的内存位置创建了第二个对象

  • 在这种情况下,它是第二个。这意味着即使
    打印id({});打印id({})
    可以打印相同的值两次,每次调用都针对一个不同的对象。

    您可能还对这个问题感兴趣:非常酷的edge case,感谢您的分享。Python的
    id()
    使用内存地址(至少在CPython实现中)作为对象的id。它只是在单个时间点上的唯一标识符,而不是在程序的整个生命周期中的唯一标识符。这在文档中是明确的:注意这是非常依赖于实现的:在第一个示例中调用四次
    id()
    ,在PyPy中会得到不同的值(在第一次调用之后,它们会下降16),在Jython和IronPython中(它们每次增加一个)。@DSM你说得对,它完全依赖于实现。确切的值甚至比这个还要糟糕:在CPython上,使用默认的PyPy配置,这些值是内存地址,在相同程序的相同运行之间可能会有所不同。回答得很好,感谢您解释了“缓存”(我认为这是一种相当可疑的优化)