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