【问题标题】:Deleting inherited dict elements in python在python中删除继承的dict元素
【发布时间】:2015-07-24 18:13:21
【问题描述】:

我有一个要销毁的对象的字典,如下所示。

class Elem:
    def __init__(self, name):
       self.name = name
    .
    .
    def __del__(self):
       print('destroying elem' + self.name)

class DerivedDict(dict):
    def __init__(self):
       super(DerivedDict, self).__init__()

    def __del__():
        for k in self.keys():
            del self[k]


elem = Elem('myname')
ddict = DerivedDict()
ddict['myname'] = elem

# this line should delete the both the elem the entry in ddict.
del ddict

当我尝试这个时,我得到了这个错误

RuntimeError: dictionary changed size during iteration

【问题讨论】:

  • 我收到此错误,这可能是与版本相关的差异,因为在 Python 3 中他们更改了 dict.keys()
  • @Exellan:这正是我正在尝试的例子。我使用的python版本3.4.3
  • 你真的需要在这些类中的任何一个中显式的析构函数吗? del ddict 使用默认析构函数将清理 ddict 及其元素,假设没有其他对这些元素的引用。
  • 当这些项目被删除时,我会在日志中打印一些内容。有没有其他方法可以做到这一点,而不使用显式的析构函数?

标签: python python-3.x dictionary destructor


【解决方案1】:

您使用的是 Python 3.x,“keys”方法为您提供了字典键的实时视图。当这些更改时,由于您删除了项目,Python 无法始终如一地继续迭代它们。

要修复它,只需将您对 self.keys 的调用传递给 list 构造函数:因此您会得到一个列表,其中包含迭代前现有键的快照:

def __del__():
    for k in list(self.keys()):
        del self[k]

现在,这里和那里有一些技巧可以正确地对 dict 进行子类化,这可能会让你大吃一惊。如果您想要的唯一行为是在 dict 删除时明确删除您的元素,则根本不需要这样做 - 否则,请参阅有关 collection.UserDict 的文档 - 这使得子类化更容易,或者 collections.abc.MutableSequence - 两者都将保证你完全 dict 行为需要覆盖最少的一组方法。

另一个注意事项:在 Python 中依赖 __del__ 在您的对象超出范围时实际运行并不被认为是好的做法:可能还有其他对它们的引用,它们 del self.key[x] 只是 不会在对象上调用__del__ 方法。并且在解释器关闭期间(在程序结束时),根本无法保证即使对于不再正确引用的对象也会调用 __del__

你最好添加一个显式的delete(不是特殊的__del__)方法并调用它,而不是依赖del语句机制。

【讨论】:

    【解决方案2】:

    迭代时最好不要删除项目。实际上我认为没有必要覆盖__del__。简单地使用:

    class DerivedDict(dict):
        def __init__(self):
           super(DerivedDict, self).__init__()
    

    这也会导致__del__Elem 被调用。

    【讨论】:

    • *对我感到羞耻 - 我刚刚编辑了你的问题,当时我去编辑我的问题以包含关于 __del__ 的旁注。我现在已经回滚了。
    • 没关系。毕竟,您的回答被接受了。恭喜。
    猜你喜欢
    • 2011-11-15
    • 2019-10-20
    • 1970-01-01
    • 2010-10-17
    • 2011-04-10
    • 1970-01-01
    • 2012-02-12
    • 2020-01-02
    相关资源
    最近更新 更多