Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中:如果一个对象只在列表中被引用,如何从列表中删除它?_Python_List_Object_Reference_Garbage Collection - Fatal编程技术网

在Python中:如果一个对象只在列表中被引用,如何从列表中删除它?

在Python中:如果一个对象只在列表中被引用,如何从列表中删除它?,python,list,object,reference,garbage-collection,Python,List,Object,Reference,Garbage Collection,我希望跟踪当前正在使用的特定类型的对象。例如:跟踪类的所有实例或元类创建的所有类 很容易跟踪这样的实例: class A(): instances = [] def __init__(self): self.instances.append(self) 但是,如果一个实例没有被引用到该列表之外的任何地方,它就不再需要了,我不想在一个潜在的耗时循环中处理该实例 我尝试使用sys.getrefcount删除仅在列表中引用的对象 for i in A.instance

我希望跟踪当前正在使用的特定类型的对象。例如:跟踪类的所有实例或元类创建的所有类

很容易跟踪这样的实例:

class A():
    instances = []
    def __init__(self):
        self.instances.append(self)
但是,如果一个实例没有被引用到该列表之外的任何地方,它就不再需要了,我不想在一个潜在的耗时循环中处理该实例

我尝试使用sys.getrefcount删除仅在列表中引用的对象

for i in A.instances:
    if sys.getrefcount(i) <=3: # in the list, in the loop and in getrefcount
        # collect and remove after the loop
另一种方法是复制对象,然后删除列表,检查哪些对象已被安排进行垃圾收集,并在最后一步删除这些对象。比如:

Copy = copy(A.instances)
del A.instances
A.instances = [i for i in Copy if not copy_of_i_is_in_GC(i)]

当引用计数变为0时,不必立即删除对象。我只是不想在不再使用的对象上浪费太多资源。

试试
gc.get\u referers(obj)


解决这个问题的标准方法是通过。基本思想是保留对对象的弱引用列表,而不是对象本身,并定期从列表中删除死弱引用


对于字典和集合,有一些更为抽象的类型,例如
weakref.weakkeydivision()
,当您希望在更复杂的位置(如字典的键)放置弱引用时,可以使用这些类型。这些类型不需要手动修剪。

这个答案与Kevin的答案相同,但我正在编写一个带有弱引用的示例实现,并将其发布在这里。使用弱引用解决了对象被
self.instance
列表引用的问题,因此它永远不会被删除

为对象创建弱引用的一个好处是,删除对象时可以包含回调。存在诸如程序退出时回调未发生等问题。。。但这可能正是你想要的

import threading
import weakref

class A(object):
    instances = []
    lock = threading.RLock()

    @classmethod
    def _cleanup_ref(cls, ref):
        print('cleanup') # debug
        with cls.lock:
            try:
                cls.instances.remove(ref)
            except ValueError:
                pass

    def __init__(self):
        with self.lock:
            self.instances.append(weakref.ref(self, self._cleanup_ref))

# test
test = [A() for _ in range(3)]
for i in range(3,-1,-1):
    assert len(A.instances) == i
    if test:
        test.pop()

print("see if 3 are removed at exit")
test = [A() for _ in range(3)]

感谢@Barmar指出使用weakref。我们可以将它与
\uuu del\uu
方法结合起来,实现类的自我管理实例列表。因此,OP职位中的
A类
可以扩展为:

from weakref import ref
class A():
    instances = []
    def __init__(self):
        self.instances.append(ref(self))

    @staticmethod
    def __del__():
      if A:
        A.instances = [i for i in A.instances if not i() is None]
测试

#python2.7
print dict((len(A.instances), A()) for i in range(5)).keys() # 0,1,2,3,4
print len(A.instances) # 0
析构函数
可以声明为静态方法或对象绑定方法,如
定义(self):
。后者可以通过创建对对象的另一个引用来阻止对象被破坏。这里我使用静态对象,因为不需要对死亡对象的另一个引用。上面的代码在Python2.7和3.3中都进行了测试


weakref.ref
回调的行为类似于
\uuu del\uuu
,只是它绑定到“weakref”对象。因此,如果使用相同的回调函数为同一对象创建多个weakrefs,则调用它的时间将与weakrefs的数量完全相同。

请使用不应是静态方法的注释。另外,
noti()是None
写得更好,因为
i()不是None
。此外,正如tdelaney所示,weakref.ref已经提供了在对象被销毁时添加回调的方法。@Bakuriu:感谢您的评论,请参阅更新的答案,以了解Python shell(3.5.1)中关于
\u del\u
weakref.ref
的讨论测试循环中的断言失败,因为在循环第二次到达断言时未调用清除回调。在assert语句之前或test.pop()之后将任何内容打印到stdout都会修复此问题。所以,将“False”放在“assert”之前可以修复它,而将“None”放在前面并不能修复它。@uzumaki很有趣。我用Python 3.4进行了测试。我不明白为什么在3.5年内没有发生回调。
from weakref import ref
class A():
    instances = []
    def __init__(self):
        self.instances.append(ref(self))

    @staticmethod
    def __del__():
      if A:
        A.instances = [i for i in A.instances if not i() is None]
#python2.7
print dict((len(A.instances), A()) for i in range(5)).keys() # 0,1,2,3,4
print len(A.instances) # 0