我希望能够获得对类的任何现有对象实例的引用元组。我想出的是:
import gc
def instances(theClass):
instances = []
gc.collect()
for i in gc.get_referrers(theClass):
if isinstance(i, theClass):
instances.append(i)
return tuple(instances)
如果在Python intepreter提示符下输入上述代码,则可以执行以下操作:
>>> class MyClass(object):
>>> pass
>>> c = MyClass()
>>> instances(MyClass)
(<__main__.MyClass object at 0x100c616d0>,)
万岁。但似乎gc.collect()
似乎并没有在函数内部做任何事情:
>>> del c
>>> instances(MyClass)
(<__main__.MyClass object at 0x100c616d0>,)
但gc.collect()
在函数外部时起作用:
>>> del c
>>> gc.collect()
>>> instances(MyClass)
()
所以,我的问题是:如何在函数内部gc.collect()
实际完成一个完整的集合(为什么它不能按原样运行)?带有推论的问题:是否有更好的方法来实现返回元组的相同目标,该元组具有对特定类的对象实例的引用?
注意:这都是在Python 2.7.3中尝试过的。我还没有在Python 3中尝试过它,但我的目标是拥有一个可以工作的功能(或者至少可以用2to3转换)。
编辑(下面的回答)澄清问题实际上是关于交互模式,而不是gc.collect()
功能本身。
答案 0 :(得分:4)
当你在交互模式下工作时,有一个神奇的内置变量_
,它保存你运行的最后一个表达式语句的结果:
>>> 3 + 4
7
>>> _
7
当您删除c
变量时,del c
不是表达式,因此_
不变:
>>> c = MyClass()
>>> instances(MyClass)
(<__main__.MyClass object at 0x00000000022E1748>,)
>>> del c
>>> _
(<__main__.MyClass object at 0x00000000022E1748>,)
_
保留对MyClass
实例的引用。当您致电gc.collect()
时,这是一个表达式,因此gc.collect()
的返回值会替换_
的旧值,最后会收集c
。它与垃圾收集器没有任何关系;任何表达式都可以:
>>> 4
4
>>> instances(MyClass)
()
答案 1 :(得分:1)
我认为有一种更简单,更可靠的方法来获取您想要的信息,而无需在gc
中进行搜索:您可以让班级负责跟踪其实例。
这里我使用元类将实例列表附加到InstanceTracker的每个子类,并覆盖__new__
以将每个创建的实例添加到列表中。 (这是Python 3代码,它需要适应一点才能使用Python 2.)
class InstanceTrackerMeta(type):
def __new__(meta, name, bases, dct):
cls = super().__new__(meta, name, bases, dct)
cls.instances = []
return cls
class InstanceTracker(metaclass=InstanceTrackerMeta):
def __new__(cls, *args, **kwargs):
instance = super().__new__(cls, *args, **kwargs)
cls.instances.append(instance)
return instance
# subclass InstanceTracker to get a class which remembers its instances
class MyClass(InstanceTracker):
pass
c = MyClass()
print(MyClass.instances)
# [<__main__.MyClass object at 0x107b9d9b0>]
注意:此代码可能需要调整,具体取决于您是否要跟踪子类的实例等。如果您希望在垃圾回收时删除实例,则需要覆盖__del__
中的InstanceTracker
。
如果您只需要跟踪系统中某个类的实例,您也可以简化它以消除元类。