如何在python中获取某个类的所有实例?

时间:2014-01-15 22:33:43

标签: python class

有人问过类似的问题[问题]:Printing all instances of a class。 虽然我不太关心打印它们,但我宁愿知道目前有多少实例是“实时”的。 此实例捕获的原因更像是设置预定作业,每小时检查这些“实时”未处理实例并丰富数据。之后,要么设置此实例中的标志,要么只删除此实例。 Torsten Marek在[问题]中的回答:Printing all instances of a class使用weakrefs需要为这种类型的每个类调用基类构造函数,是否可以自动执行此操作?或者我们可以通过其他方法获取所有实例?

4 个答案:

答案 0 :(得分:4)

您可以自己跟踪它(请参阅其他答案)或询问垃圾收集器:

import gc

class Foo(object):
   pass

foo1, foo2 = Foo(), Foo()

foocount = sum(1 for o in gc.get_referrers(Foo) if o.__class__ is Foo)

如果您拥有大量对象,这可能会有点慢,但它通常不会太糟糕,而且它的优点是可以轻松地与其他人的代码一起使用。

如果您希望它也能捕获subclasess,请更改生成器表达式中的if子句:... if isinstance(o, Foo))

注意:使用o.__class__而不是type(o),因此它适用于旧式类。

答案 1 :(得分:1)

当然,将计数存储在类属性中:

class CountedMixin(object):
    count = 0
    def __init__(self, *args, **kwargs):
        type(self).count += 1
        super().__init__(*args, **kwargs)
    def __del__(self):
        type(self).count -= 1
        try:
            super().__del__()
        except AttributeError:
            pass

你可以使用装饰器或元类比使用基类稍微更神奇,或者如果它可以稍微不那么通用就更简单(我试图使它适合任何合理的多继承层次结构中的任何位置) ,你通常不需要担心...),但基本上,这就是它的全部内容。

如果你想让实例本身(或者更好的是,对它们进行弱化),而不是只计算它们,只需用count=0替换instances=set(),然后执行instances.add(self)而不是count += 1等等(但是,您可能想要 weakref self,而不是self。)

答案 2 :(得分:1)

如果您只想让它适用于CPython,并且您对“live”的定义可能有点松懈,还有另一种方法可以 对调试/内省有用:< / p>

>>> import gc
>>> class Foo(object): pass
>>> spam, eggs = Foo(), Foo()
>>> foos = [obj for obj in gc.get_objects() if isinstance(obj, Foo)]
>>> foos
[<__main__.Foo at 0x1153f0190>, <__main__.Foo at 0x1153f0210>]
>>> del spam
>>> foos = [obj for obj in gc.get_objects() if isinstance(obj, Foo)]
>>> foos
[<__main__.Foo at 0x1153f0190>, <__main__.Foo at 0x1153f0210>]
>>> del foos
>>> foos = [obj for obj in gc.get_objects() if isinstance(obj, Foo)]
>>> foos
[<__main__.Foo at 0x1153f0190>]

请注意,删除spam实际上并不会使其失效,因为我们仍然在foos中引用了同一个对象。并且重新分配foos并没有帮助,因为显然对get_objects的调用发生在旧版本发布之前。但是一旦我们停止提及它,它最终会消失。

解决这个问题的唯一方法是使用weakrefs。

当然,在有或没有弱点的大型系统中,这将非常慢。

答案 3 :(得分:0)

我不能对善意的答案发表评论,因此我将评论写成答案:

gc.get_referrers(<ClassName>)的解决方案不适用于python 3中的继承类。方法gc.get_referrers(<ClassName>)不返回从<ClassName>继承的类的任何实例。

相反,您需要使用速度慢得多的gc.get_objects(),因为它会返回完整的对象列表。但是在单元测试的情况下,你只想确保你的对象在测试后被删除(没有循环引用),它应该足够快。

另外,在检查实例数量之前,不要忘记调用gc.collect(),以确保所有未引用的实例都被删除。

我也看到了弱引用的问题,这也是以这种方式计算的。弱引用的问题是,引用的对象可能不再存在,因此isinstance(Instance, Class)可能会失败并显示有关不存在的弱引用的错误。

这是一个简单的代码示例:

import gc

def getInstances(Class):
  gc.collect()
  Number = 0
  InstanceList = gc.get_objects()
  for Instance in InstanceList:
    if 'weakproxy' not in str(type(Instance)): # avoid weak references
      if isinstance(Instance, Class):
        Number += 1

  return Number