【问题标题】:Is it possible to delete an instance of a class that automatically removes it from all lists in which it is an element?是否可以删除一个类的实例,该实例会自动将其从作为元素的所有列表中删除?
【发布时间】:2014-04-29 09:45:27
【问题描述】:

我有一个class 的实例,它作为一个元素出现在多个lists 中。我想删除该实例并同时将其从它作为元素的每个 list 中删除。这可能吗?

【问题讨论】:

  • 一切皆有可能(我能想到一种方法来做你所说的),但我想不出一种基本上不是黑客的方法。
  • 这种听起来像XY problem为什么你想这样做?当您点击列表中的“过期”实例时,您可能可以做一些更好的事情,例如 throw 然后处理特定异常。
  • 如果您确实想要这样的东西,我们需要定义问题的边界。像这样的东西能被“删除”到什么程度?如果我将其中一个列表序列化为您的调用者之一,您是否希望能够找到该文件并对其进行编辑? (一个极端的例子只是为了展示这里可能存在的大量范围问题。)
  • 一种可能的“hack”方法是维护一个从元素到列表引用列表的字典,每次将元素添加到列表时都必须更新该字典。或者,您可以将此列表列表保留在对象本身中,并覆盖其析构函数以将其从所有列表中删除。
  • 我的动机如下:我正在创建一个基于代理的模拟。 Agent() 是相关的类。代理有时必须从模拟中移除。对我来说,删除实例会释放内存似乎很直观。如果这也将实例从它所属的列表中删除,那就太好了。

标签: python list class instance del


【解决方案1】:

对此的一个答案是始终允许您放入列表中的对象管理列表成员资格。例如,而不是说

listA.append(objectA)

你会使用

objectA.addToList(listA)

这将允许您在内部存储包含objectA 的所有列表的列表。那么,当你想删除objectA时,你需要调用这样一个方法:

def cleanup(self):
    for listToClean in myLists:
        listToClean.remove(self)

这确实对您的程序施加了一些严格的限制——例如,如果一个副本由这些列表之一组成,那么对象将不会引用该副本。您必须假设列表的任何副本(不要忘记切片也是副本)可能包含过时的对象,这意味着您希望尽可能频繁地使用原始列表.

【讨论】:

  • 不错的 OO 解决方案。如果您想在并行或多线程环境中使用它,让某些对象修改它不一定封装的任意列表可能会导致一些实际问题。
【解决方案2】:

你可以考虑使用weakref.refs:

class WeakRefList(list):
    def __init__(self, args):
        list.__init__(self, [self.weak(item) for item in args])
    def append(self, item):
        list.append(self, self.weak(item))
    def weak(self, item):
        return weakref.ref(item, self.remove)

class Object(object):
    def __init__(self, name):
        self.name = name

orig = [Object('Foo'), Object('Bar')]
weaklist = WeakRefList(orig)
orig.append(Object('Baz'))
weaklist.append(orig[-1])
print(orig[0])
# <__main__.Object object at 0xb748aaac> 
print(weaklist)
# [<weakref at 0xb7487a54; to 'Object' at 0xb748aaac>,
#  <weakref at 0xb7487a7c; to 'Object' at 0xb748ab6c>,
#  <weakref at 0xb7487aa4; to 'Object' at 0xb748ac2c>]

您调用weakref 来恢复原始对象。如果不存在,调用wearef会返回None

print(weaklist[0]())
# <__main__.Object object at 0xb748aaac>

它返回完全相同的对象:

print(orig[0] is weaklist[0](), id(orig[0]), id(weaklist[0]()))
# (True, 3074992812L, 3074992812L)

你可以像往常一样访问它的属性(或方法):

print(weaklist[0]().name)
# Foo

for item in weaklist:
    print(item)
    # <weakref at 0xb7487a54; to 'Object' at 0xb748aaac>
    # <weakref at 0xb7487a7c; to 'Object' at 0xb748ab6c>
    # <weakref at 0xb7487aa4; to 'Object' at 0xb748ac2c>

print([item.name for item in orig])
# ['Foo', 'Bar', 'Baz']
print([item().name for item in weaklist])
# ['Foo', 'Bar', 'Baz']

最后,这是您要查找的属性:从 orig 删除项目也会自动从 weaklist 删除它们:

while orig:
    item = orig.pop()
    del item
print(orig)        
# []
print(weaklist)
# []

【讨论】:

    猜你喜欢
    • 2022-11-21
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多