39

如果字典包含可变对象或自定义类的对象(例如查询集,甚至是 DateTime),那么调用clear()字典会从内存中删除这些对象吗?它的行为与遍历 dict 和deleting 的行为是否不同?

例如。考虑

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]

?

4

7 回答 7

64

dicts 上的 Python 文档指出,在del d[key]删除每个键d[key]的同时从字典d.clear()中删除,所以基本上它们的行为是相同的。

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

于 2012-05-04T11:29:22.267 回答
15

事实上,两者之间存在非常小的差异。clear()将释放字典中使用的哈希集的内存,而删除密钥则不会。

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
于 2015-05-29T01:55:24.947 回答
5

它的行为与遍历 dict 和deleting 的行为是否不同?

这里值得注意的是,任何实现MutableMapping抽象基类的自定义类都可以clear()作为“免费”的 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 中工作。

于 2014-06-06T19:39:02.530 回答
4

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

当然,如果没有其他对它们的引用,它们可能会变成垃圾回收。

于 2012-05-04T10:17:03.140 回答
1

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

于 2012-05-04T11:04:53.090 回答
1

del 命令删除列表中特定项目的引用, clear 命令清除所有键值对,因此功能相同,它们都取消引用和从内存中删除它的其余任务由垃圾收集器完成

于 2016-01-20T09:24:10.607 回答
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()

于 2019-05-05T07:09:44.817 回答