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

如何在python中获取某个类的所有实例?,python,class,Python,Class,有人问了一个类似的问题:。 虽然我不太关心打印它们,但我更想知道有多少实例当前处于“活动”状态。 此实例捕获的原因更像是设置计划作业,每小时检查这些“活动”的未处理实例并丰富数据。在此之后,可以设置此实例中的标志,也可以删除此实例。 Torsten Marek在[问题]中的回答:使用weakrefs需要为这种类型的每一个类调用基类构造函数,有可能实现自动化吗?或者我们可以使用其他方法获取所有实例?当然,将计数存储在类属性中: class CountedMixin(object): cou

有人问了一个类似的问题:。 虽然我不太关心打印它们,但我更想知道有多少实例当前处于“活动”状态。 此实例捕获的原因更像是设置计划作业,每小时检查这些“活动”的未处理实例并丰富数据。在此之后,可以设置此实例中的标志,也可以删除此实例。
Torsten Marek在[问题]中的回答:使用weakrefs需要为这种类型的每一个类调用基类构造函数,有可能实现自动化吗?或者我们可以使用其他方法获取所有实例?

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

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
您可以使用装饰器或元类使其比基类更神奇,或者更简单,如果它不那么通用的话(我试图使其适合任何合理的多重继承层次结构中的任何地方,您通常不需要担心……),但基本上,这就是它的全部内容


如果您想拥有实例本身(或者更好地说,对它们进行weakrefs),而不仅仅是计数,只需将
count=0
替换为
instances=set()
,然后执行
instances.add(self)
而不是
count+=1
,等等。(尽管如此,您可能还是想要一个weakref来
self
,而不是
self

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

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)
如果您有很多对象,这可能会有点慢,但通常不会太糟糕,而且它的优点是您可以轻松地与其他人的代码一起使用


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

如果您只希望它适用于CPython,并且您对“live”的定义可能有点松散,那么有另一种方法可以用于调试/内省:

>>> 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>]
导入gc >>>类Foo(对象):pass >>>垃圾邮件,鸡蛋=Foo(),Foo() >>>foos=[obj代表gc.get_objects()中的obj,如果是instance(obj,Foo)] >>>福斯 [, ] >>>删除垃圾邮件 >>>foos=[obj代表gc.get_objects()中的obj,如果是instance(obj,Foo)] >>>福斯 [, ] >>>德尔福斯 >>>foos=[obj代表gc.get_objects()中的obj,如果是instance(obj,Foo)] >>>福斯 [] 请注意,删除
spam
实际上并没有使其成为非活动的,因为我们仍然在
foos
中获得了对同一对象的引用。而重新分配
foos
也没有帮助,因为显然对
get\u objects
的调用发生在旧版本发布之前。但一旦我们停止重新分配,它最终就消失了向它运送

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


当然,在一个大型系统中,无论有无漏洞,这都会非常缓慢。

我无法对kindall的答案发表评论,因此我将我的评论作为答案:

使用
gc.get\u referers()
的解决方案不适用于python 3中的继承类。方法
gc.get\u referers()
不返回从
继承的类的任何实例

相反,您需要使用
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

可能值得一提的是:与任何依赖于
\uu del\uu
方法的操作一样,这可能会导致不直观的行为。例如:
CountedMixin()
导致
CountedMixin.count
增加一段时间,即使无法访问新对象。
\uuu del\uuu
也会阻止循环垃圾收集器处理这些对象objects@gnibbler:是的,如果您想创建对象的循环并钩住它们的销毁,您需要将自己的循环断路器添加到
gc.callbacks
。这是
\uuu count
可能比
count
+1更好的地方之一。这很可能是每小时检查一次的好方法,并且没有使用
\uu del\uu