OrderedDict与Python中的Dict

时间:2014-07-31 10:18:50

标签: python dictionary ordereddictionary

Tim Peter's answer中,“有没有理由不使用有序词典”,他说

  

OrderedDict是dict的子类。

     

速度并不慢很多,但至少使用普通字典使内存翻倍。

现在,在浏览particular question时,我尝试使用ipython进行一些示例检查,这两项检查都与之前的推理相矛盾:

  1. dictOrderedDict的大小相同
  2. OrderedDict上操作比在dict上操作时间大约多7-8倍(因此慢得多)
  3. 有人可以向我解释我在推理中出错的地方吗?


    创建一个大型Dict和OrderedDict并比较大小:

    import sys
    import random
    from collections import OrderedDict
    
    test_dict = {}
    test_ordered_dict = OrderedDict()
    
    for key in range(10000):
        test_dict[key] = random.random()
        test_ordered_dict[key] = random.random()
    
    sys.getsizeof(test_dict)
    786712
    
    sys.getsizeof(test_ordered_dict)
    786712
    

    使用%timeit检查插入时间:

    import sys
    import random
    from collections import OrderedDict
    
    def operate_on_dict(r):
        test_dict = {}
        for key in range(r):
            test_dict[key] = random.random()
    
    def operate_on_ordered_dict(r):
        test_ordered_dict = OrderedDict()
        for key in range(r):
            test_ordered_dict[key] = random.random()
    
    %timeit for x in range(100): operate_on_ordered_dict(100)
    100 loops, best of 3: 9.24 ms per loop
    
    %timeit for x in range(100): operate_on_dict(100)
    1000 loops, best of 3: 1.23 ms per loop
    

1 个答案:

答案 0 :(得分:10)

我认为尺寸问题是因为Python 2.X implementation of OrderedDict中没有定义__sizeof__方法,所以它简单地回退到dict的__sizeof__方法。 / p>

为了在此处证明这一点,我在此处创建了一个A类,其中list扩展了foo并添加了另一个方法class A(list): def __getitem__(self, k): return list.__getitem__(self, k) def foo(self): print 'abcde' >>> a = A(range(1000)) >>> b = list(range(1000)) 来检查是否会影响大小。

sys.getsizeof

>>> sys.getsizeof(a), sys.getsizeof(b) (9120, 9120) 仍然返回相同的尺寸:

A

当然>>> %%timeit ... for _ in xrange(1000): ... a[_] ... 1000 loops, best of 3: 449 µs per loop >>> %%timeit for _ in xrange(1000): b[_] ... 10000 loops, best of 3: 52 µs per loop 会变慢,因为它的方法在Python中运行而list的方法将在纯C中运行。

def __sizeof__(self):
    sizeof = _sys.getsizeof
    n = len(self) + 1                       # number of links including root
    size = sizeof(self.__dict__)            # instance dictionary
    size += sizeof(self.__map) * 2          # internal dict and inherited dict
    size += sizeof(self.__hardroot) * n     # link objects
    size += sizeof(self.__root) * n         # proxy objects
    return size

这似乎在Python 3中得到修复,现在有一个定义良好的__sizeof__方法:

{{1}}