dictionary的clear()方法是否从内存中删除了所有与项目相关的对象?

时间:2012-05-04 10:13:51

标签: python memory dictionary

如果字典包含可变对象或自定义类的对象(比如查询集,甚至是DateTime),那么在字典上调用clear()会从内存中删除这些对象吗? 它是否与循环通过dict和del使用它们的行为不同?

例如。 考虑

class MyClass(object):
    '''Test Class.'''

my_obj_1 = MyClass()
my_obj_2 = MyClass()

my_dict = { 'foo' : my_obj_1, 'bar' : my_obj_2 }

然后是

my_dict.clear()

相同
for key in my_dict.keys():
    del my_dict[key]

7 个答案:

答案 0 :(得分:44)

Python documentation on dicts声明del d[key]从字典中删除d[key],而d.clear()删除了所有密钥,所以基本上他们的行为是相同的。

关于内存问题,在Python中“删除”时,基本上是删除了对象的引用。当某个对象未被任何变量或其他对象引用或变得无法访问时,它将变为垃圾,并且可以从内存中删除。 Python有一个垃圾收集器不时它完成了检查哪些对象是垃圾并释放为它们分配的内存的工作。 如果您从字典中删除的对象被其他变量引用,那么它仍然可以访问,因此它不是垃圾,因此不会被删除。如果你有兴趣阅读一般的垃圾收集和特别是python的垃圾收集,我会给你留下一些链接。

答案 1 :(得分:5)

  

它的行为与循环通过dict和del是否有所不同?

值得注意的是,任何实现MutableMapping抽象基类的自定义类都将clear()作为" free" mixin方法。

为了实例化MutableMapping子类,您需要覆盖的唯一方法是:

__getitem__, __setitem__, __delitem__, __iter__, __len__

由于您可以按照自己喜欢的方式将数据存储在地图类中,因此clear()可以找出如何实际清除数据的唯一方法是使用这五种方法中的一种或多种。现在,您可能会猜测clear()正在使用哪些方法,但为什么我们可以进行实验?

import collections

class MyMap(collections.MutableMapping):
    def __init__(self, mydict):
        self._top_secret_data = mydict

    def __getitem__(self, key):
        print 'getitem'
        return self._top_secret_data[key]

    def __setitem__(self, key, value):
        raise Exception('where did you want that?')

    def __len__(self):
        raise Exception('a gentleman never tells')

    def __delitem__(self, key):
        print '[shredding intensifies]'
        del self._top_secret_data[key]

    def __iter__(self):
        def keygen():
            for key in self._top_secret_data:
                print 'faster! faster!'
                yield key
        return iter(keygen())

使用上面定义的类,很容易看出clear()是如何实现的:

>>> m = MyMap({1:'a', 2:'b', 3:'c'})
>>> m.clear()
faster! faster!
getitem
[shredding intensifies]
faster! faster!
getitem
[shredding intensifies]
faster! faster!
getitem
[shredding intensifies]
>>> 

换句话说,clear() mixin方法基本上实现为for key in self: del self[key]

现在,免责声明:内置类型(例如dict)在C中实现,因此dict.clear方法可能与for key in mydict: del mydict[key]字面上不一致。我希望在幕后进行一些优化,也许是一个完全不同的策略 - 但希望这个例子可以让你了解如何期望 clear()方法在Python中工作。

答案 2 :(得分:5)

事实上,两者之间存在很小的差异。 clear()将释放dict中使用的hashset的内存,而删除密钥则不会。

a = dict.fromkeys(range(1000))

In [10]: sys.getsizeof(a)
Out[10]: 49432

In [11]: a.clear()

In [12]: sys.getsizeof(a)
Out[12]: 280

In [13]: a = dict.fromkeys(range(1000))

In [14]: for i in range(1000):
   ....:     del a[i]
   ....:     

In [15]: sys.getsizeof(a)
Out[15]: 49432

答案 3 :(得分:3)

它与调用del d['foo']相同 - 它只是删除条目,但它不会影响键或值本身。

当然,如果没有其他参考,它们可能会成为垃圾收集品。

答案 4 :(得分:1)

在您的情况下,共享两个MyClass个对象。仍然可以通过my_obj_1my_obj_2访问它们。

答案 5 :(得分:1)

del命令删除列表中特定项的引用,clear命令清除所有键值对,所以功能相同它们都是取消引用和休息任务从内存中删除它是由垃圾完成的集电极

答案 6 :(得分:0)

您是否尝试过运行代码? Python 3.7的以下代码会引发异常! “ RuntimeError:字典在迭代过程中更改了大小”

for key in my_dict.keys():
    del my_dict[key]

所有先前的答案都是好的。我只是想补充一些关于del和clear区别的观点:

  1. my_dict.clear(); 删除字典中的所有项目,并使其等同于空字典。注意:您仍然可以根据需要添加项目!
  2. del my_dict; 使my_dict的对象被删除,并且符合垃圾回收的条件(my_dict不再可用)!因此,如果您尝试添加/访问任何项目,那么您将获得例外。
  3. 此外,您还声明了两个变量my_obj_1和my_obj_2;即使删除/清除my_dict,这两个变量仍保留对MyClass对象的引用,直到my_obj_1和my_obj_2超出范围时,它们才会消失。因此,如果MyClass对象保存内存(例如列表或其他内容),那么如果您打算通过删除/清除my_dict释放内存,则不会发生!

    class MyClass(object):     '''测试班。'''

    my_obj_1 = MyClass() my_obj_2 = MyClass()