字典是否仅在内部存储对键和值的引用?

时间:2018-10-12 19:11:41

标签: python

我试图了解Python字典如何在内部优化其所需的内存。以下是我编写的示例代码:

 d = dict({
  "id": {
    "mm": {
      "a": 4,
      "b": 4,
      "d": 4
    },
    "nn": {
      "a": 4,
      "b": 4,
      "e": 4
    }
  }
})
print(d["id"]["mm"])
for key, value in d["id"]["mm"].items():
    print("-------------------------------------------")
    print("key : ", key, ", value : ",value)
    print("key id : ", id(key), ", value id: ",id(value))
print("===========================================")    
print(d["id"]["nn"])    
for key, value in d["id"]["nn"].items():
    print("-------------------------------------------")
    print("key : ", key, ", value : ",value)
    print("key id : ", id(key), ", value id: ",id(value))        
print("-------------------------------------------")

以下是上面代码的输出:

{'a': 4, 'b': 4, 'd': 4}
-------------------------------------------
key :  a , value :  4
key id :  31453000 , value id:  1935862320
-------------------------------------------
key :  b , value :  4
key id :  31451320 , value id:  1935862320
-------------------------------------------
key :  d , value :  4
key id :  30586728 , value id:  1935862320
===========================================
{'a': 4, 'b': 4, 'e': 4}
-------------------------------------------
key :  a , value :  4
key id :  31453000 , value id:  1935862320
-------------------------------------------
key :  b , value :  4
key id :  31451320 , value id:  1935862320
-------------------------------------------
key :  e , value :  4
key id :  30586616 , value id:  1935862320
-------------------------------------------

从上面的输出中,似乎与条目"a": 4, "b": 4相对应的键和值都在与"mm""nn"相对应的值中被重用。那么,Python字典是否仅在内部存储与键和值对应的引用以优化其内存占用量?

1 个答案:

答案 0 :(得分:1)

这与Python的dict几乎没有关系,而与在CPython中缓存小的不可变对象这一事实有很大关系。评论暗示了这一点。以下是一些详细信息:

dict只是一个键/值容器:仅此而已。这些值始终是 引用(4是对不可变整数的引用),问题是这些引用是否相同。

请注意,is关键字将比较两个对象以查看其ID是否相同。

>>> a = 123456
>>> b = 123456
>>> a is b
False
>>> id(a)
4343450000
>>> id(b)
4343450096
>>> c = 4
>>> d = 4
>>> c is d
True
>>> id(c)
4335519152
>>> id(d)
4335519152

字符串也是不可变的,碰巧以类似的方式缓存:

>>> a = "some_string"
>>> b = "some_string"
>>> a is b
True
>>> id(a)
4343486192
>>> id(b)
4343486192
>>> c = "some_really_long_string_that_cpython_wont_cache_but_it_has_to_be_pretty_stinking_large_though_so_that_it_doesn't_fit_on_screen"
>>> d = "some_really_long_string_that_cpython_wont_cache_but_it_has_to_be_pretty_stinking_large_though_so_that_it_doesn't_fit_on_screen"
>>> c is d
False
>>> id(c)
4337753760
>>> id(d)
4339036736

是否调用引用abcd(就像我在上面的玩具示例中所做的那样)无关紧要,或者将其分配给字典键/值对。

>>> x = {"a": 2*3, "b": 2*3, "c": 123*100, "d": 123*100}
>>> x["a"] is x["b"]
True
>>> x["c"] is x["d"]
False

同样,我们只是将引用存储在数据结构(dict)中。

可变对象不同:

>>> a = []
>>> b = []
>>> a is b
False

因为它们相同相同,则修改列表a会影响列表b(因为它们将成为相同引用) 。继续:

>>> a.append(1)
>>> a
[1]
>>> b
[]

但是如果同一可变对象由两个不同的引用指向,则该突变会同时反映在两个引用中(因为它们碰巧引用了同一对象):

>>> c = a # force c to be the same reference as a
>>> a is c
True
>>> a
[1]
>>> c
[1]
>>> a.append(3)
>>> a
[1, 3]
>>> c
[1, 3]

词典是否仅在内部存储对键和值的引用?

是的。但是这个特定的问题可能并不意味着您认为发布后意味着什么。往上看。还应注意,键通常是不可变的。

Python字典是否仅在内部存储与键和值相对应的引用以优化其内存占用?

是,不是。节省的内存空间与dict无关,这与以下事实有关:CPython中缓存了小的不可变对象,因此每个浮动的引用都指向 same 对象。但是,使用引用通常确实可以帮助占用内存(例如缓存,或者如果您有多个引用相同的大对象,而不是其副本在周围浮动)。

PS 。Python编程语言不能保证缓存机制。其他解释器可能具有也可能没有这种机制,因此请不要在您的代码中依赖它。比较不可变对象(假设要比较其)而不是==时最好使用is