为此,您需要某种方法来查找类的所有实例。一种方法是让类本身跟踪它的实例。不幸的是,保留对类中每个实例的引用意味着这些实例永远不会被垃圾收集。幸运的是,Python 有weakref
,它将保留对对象的引用,但不计入对 Python 内存管理的引用,因此可以像往常一样对实例进行垃圾收集。
更新实例列表的好地方是在您的__init__()
方法中。__new__()
如果您发现关注点分离更清晰,您也可以这样做。
import weakref
class Foo(object):
_instances = []
def __init__(self, value):
self.value = value
cls = type(self)
type(self)._instances.append(weakref.ref(self,
type(self)._instances.remove))
@classmethod
def iterinstances(cls):
"Returns an iterator over all instances of the class."
return (ref() for ref in cls._instances)
@classmethod
def iterattrs(cls, attr, default=None):
"Returns an iterator over a named attribute of all instances of the class."
return (getattr(ref(), attr, default) for ref in cls._instances)
现在你可以这样做:
f1, f2, f3 = Foo(1), Foo(2), Foo(3)
for v in Foo.iterattrs("value"):
print v, # prints 1 2 3
郑重声明,我和那些认为这通常是一个坏主意和/或不是你真正想要的东西的人在一起。特别是,实例的寿命可能比您预期的要长,具体取决于您传递它们的位置以及该代码对它们的作用,因此您可能并不总是拥有您认为拥有的实例。(其中一些甚至可能隐式发生。)通常最好明确一点:与其将类的各种实例存储在整个代码(和库)中的随机变量中,不如让它们的主存储库成为一个列表或其他容器,并从那里访问它们。然后您可以轻松地遍历它们并获得您想要的任何属性。但是,可能会有这样的用例,并且可以对其进行编码,所以我做到了。