Python:在交互模式下使用gc模块的不同行为
我希望能够获得对类的任何现有对象实例的引用的元组。我想到的是:Python:在交互模式下使用gc模块的不同行为,python,garbage-collection,Python,Garbage Collection,我希望能够获得对类的任何现有对象实例的引用的元组。我想到的是: 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) 如果在Pytho
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>,)
>>> del c
>>> gc.collect()
>>> instances(MyClass)
()
因此,我的问题是:如何使gc.collect()
在函数内部实际执行完整的收集(为什么它不能按原样工作)?由此产生的问题是:有没有更好的方法来实现返回一个元组并引用特定类的对象实例的相同目标
注意:这些都是在Python2.7.3中尝试过的。我还没有在Python3中尝试过它,但我的目标是拥有一个可以在这两种语言中工作的函数(或者至少可以用2to3转换)
编辑(根据下面的答案)以澄清问题实际上与交互模式有关,而不是
gc.collect()
函数本身。当您在交互模式下工作时,有一个神奇的内置变量\u
保存上次运行的表达式语句的结果:
>>> 3 + 4
7
>>> _
7
删除c
变量时,del c
不是表达式,因此\uu
不变:
>>> c = MyClass()
>>> instances(MyClass)
(<__main__.MyClass object at 0x00000000022E1748>,)
>>> del c
>>> _
(<__main__.MyClass object at 0x00000000022E1748>,)
我认为有一种更简单、更可靠的方法可以获得您想要的信息,而无需在
gc
中四处搜索:您可以让类负责跟踪其实例
在这里,我使用一个元类将实例列表附加到InstanceTracker的每个子类,并重写\uuuu new\uuuu
将每个创建的实例添加到列表中。(这是Python3代码,需要进行一些调整才能使用Python2。)
class InstanceTrackerMeta(类型):
定义新定义(元、名称、基、dct):
cls=super()
cls.instances=[]
返回cls
类InstanceTracker(元类=InstanceTrackerMeta):
定义(cls,*ARG,**kwargs):
instance=super()
cls.instances.append(实例)
返回实例
#子类InstanceTracker以获取一个记住其实例的类
类MyClass(InstanceTracker):
通过
c=MyClass()
打印(MyClass.instances)
# []
注意:这段代码可能需要调整,这取决于您是否希望跟踪子类的实例等等。如果希望在垃圾收集实例时将其删除,则需要覆盖InstanceTracker
中的\uu del\uu
。
如果您只需要跟踪系统中某个类的实例,您也可以简化它以摆脱元类。可能与您的问题无关,但是为什么要在
获取引用器
输出上调用枚举
?你从不使用索引做任何事情。如果没有必要,那可能是因为我不知道自己在做什么。我认为需要从get_referers中获取每个列表项,然后将其分配给I并在后续行中使用。您可以直接迭代:用于gc中的thing。get_referers(MyClass):if isinstance(thing,MyClass):…
我明白您的意思;我编辑了这个问题以简化它。谢谢。非常有启发性的回答。谢谢我不知道交互模式可能会产生不同的行为。我还没有尝试过将其作为脚本运行,而当我刚刚尝试时,我很高兴看到它不仅按预期运行,而且似乎根本不需要gc.collect()。@IvanX:在CPython中,gc.collect()
只进行清理。如果程序中没有引用循环,则不会发生任何事情,这可能解释了为什么在测试中不需要调用gc.collect()
。
>>> 4
4
>>> instances(MyClass)
()
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>]