I wish if it were that simple
.
Here is a longer description - I have a function that given input creates a
custom class and returns it back. The user is free to subclass that (even
more, he should do that), and of course he will make instances of those
subclasses. Now, my question is how to keep track of subclasses and their
instances, without the need for user interaction (appending them to a list,
or adding to dictionary)?
Thanks,
I guess Larry's actual question was why do *you* need to keep track of
users' instances and subclasses and don't let them keep track on their
own if/when they need it. I realize there are legitimate use cases for
this but it's not typical. Anyway, here's something to get you
started; all a user has to do is derive (directly or indirectly) from
InstanceTracker and, if a class C defines __init__,
super(C,self).__init__() should be called explicitly:
from collections import deque
from weakref import WeakKeyDictionary
class InstanceTracker(object):
def __init__(self):
try: all = self.__class__.__dict__['__instances__']
except KeyError:
self.__class__.__instances__ = all = WeakKeyDictionary()
all[self] = None
def iter_instances(cls):
return iter(cls.__dict__.get('__instances__',[]))
def iter_descendant_classes(cls):
memo = set()
unvisited = deque(cls.__subclasses__())
while unvisited:
top = unvisited.popleft()
if top not in memo:
memo.add(top); yield top
unvisited.extend(top.__subclasses__())
#----- example --------------------------------------
if __name__ == '__main__':
class A(InstanceTracker): pass
class B1(A): pass
class B2(A): pass
class C1(B1,B2):
def __init__(self):
super(C1,self).__init__()
class C2(B1,B2): pass
class D(C1,C2): pass
items = [A(),B1(),B2(),C1(),C1(),D(),A(),B2()]
print ' * Instances per class'
for c in iter_descendant_classes(A):
print c, list(iter_instances(c))
print ' * Instances per class (after delete)'
del items
for c in iter_descendant_classes(A):
print c, list(iter_instances(c))
HTH,
George