如何在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