Python 字典大小与对象大小效率

Python dictionary size vs object size efficiency

有人可以解释在下面的例子中使用 dictionaryobjects 操作时 memory 在幕后发生了什么:

In [52]: class O(object):
....:         var1 = 'asdfasdfasfasdfasdfasdfasdf'
....:         var2 = 255
....: 

In [53]: dt = {'var1': 'asdfasdfasfasdfasdfasdfasdf', 'var2': 255}

In [55]: o = O()

In [57]: sys.getsizeof(o)
Out[57]: 64

In [58]: sys.getsizeof(dt)
Out[58]: 280

根据上面的值,接下来的事情很奇怪

In [68]: sys.getsizeof(o.var1)
Out[68]: 64

In [69]: sys.getsizeof(o.var2)
Out[69]: 24

In [70]: sys.getsizeof(dt['var1'])
Out[70]: 64

In [71]: sys.getsizeof(dt['var2'])
Out[71]: 24

数据结构中的值大小相同,但类型之间的差异让我想知道幕后发生了什么?

该示例是否使 objectsdictionaries 更有效?

我使用 Ubuntu 14.04 和 Python 2.7.6

两个对象的简单比较表明字典比简单的对象复杂得多 class:

>>> dt = {}
>>> dir(dt)
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__',  
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__',  
'__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__',  
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__',  
'__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get',  
'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem',  
'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']

反对:

>>> class O(object):
...   var1 = 'asdfasdfasfasdfasdfasdfasdf'
...   var2 = 255
... 
>>> o = O()
>>> dir(o)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
 '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__',  
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',  
'__str__', '__subclasshook__', '__weakref__', 'var1', 'var2']

请注意,sys.getsizeof 为您提供了 对象本身的大小 ,但这并不是全部。对象具有各种 属性 ,这些属性也会影响整体内存占用。例如,一个 class 的实例有一个 __dict__,它保存它的属性值:

>>> o = O()
>>> o.__dict__
{}
>>> sys.getsizeof(o.__dict__)
140

注意三件有趣的事情:

  1. 这也是一个字典 - 这个数据结构在 Python 中被 大量使用 ,因此得到了非常好的优化;
  2. o.__dict__中没有任何内容,因为var1var2class属性,存储在O,不是实例属性;和
  3. 即使 o.__dict__ 中没有任何内容,它仍然与 dt 大小相同,因为字典已使用足够的 space 初始化 (IIRC) 八个键以避免频繁调整大小您向它们添加项目(有关词典实现的更多信息,请参阅 "The Mighty Dictionary")。

另请注意,如果我们在两种情况下比较实例 加上 class 的大小,这是一个更公平的比较,差距会缩小:

>>> sys.getsizeof(o) + sys.getsizeof(O)
484
>>> sys.getsizeof(dt) + sys.getsizeof(dict)
576

Does the example makes objects more effective over dictionaries?

完全没有;一方面,正如我所展示的,对象通常是 使用 字典实现的(有一种方法可以不为每个实例创建 __dict__,通过定义 __slots__ class 上的预定义属性,但我不会在这里深入讨论)和字典本身就是对象(尽管内置类型略有不同,原因我不会详述)!

一般来说,不要担心内存细节,除非它成为问题 - 如果你需要状态 行为(属性 方法),如果你只需要状态就使用字典。