Keeping track of subclasses and instances?

K

Karlo Lozovina

Hi,

what's the best way to keep track of user-made subclasses, and instances of
those subclasses? I just need a pointer in a right direction... thanks.
 
L

Larry Bates

Karlo said:
Hi,

what's the best way to keep track of user-made subclasses, and instances of
those subclasses? I just need a pointer in a right direction... thanks.
I'm not completely sure I understand the question but here goes. Instances of
classes are classes can be stored in lists or dictionaries. In lists you
reference them via their index (or iterate over them) and in dictionaries you
can give them a name that is used as a key.

Hope this helps.

-Larry
 
K

Karlo Lozovina

Larry said:
I'm not completely sure I understand the question but here goes.
Instances of
classes are classes can be stored in lists or dictionaries. In lists you
reference them via their index (or iterate over them) and in dictionaries
you can give them a name that is used as a key.

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,
 
G

George Sakkis

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
 
S

Steven D'Aprano

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)?

The real question is why you think you need to keep track of them instead
of letting the user and/or Python keep track of them, like any other
object.
 
S

Steven D'Aprano

This recipe does what you want, with the intent of providing automatic
finalization of the instances, but you should be able to tweak it to do
everything you wish:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/523007


Well, that answers my earlier question about why you might want to track
instances. But it seems like an unnecessarily complicated way of doing it.

From your recipe:

[module deallocating.py]

import logging

class C(object):
def __init__(self):
logging.warn('Allocating resource ...')
def __del__(self):
logging.warn('De-allocating resource ...')
print 'THIS IS NEVER REACHED!'

if __name__ == '__main__':
c = C()


Is there a problem with writing C like this?

class C(object):
def __init__(self):
logging.warn('Allocating resource ...')
self.__log = logging.warn
def __del__(self):
self.__log('De-allocating resource ...')
print 'THIS IS REACHED!'



It works for me. Have I missed something?
 
A

Andreas Kraemer

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,

What about the following solution?

class Meta(type):
def __new__(mcl,*args,**kw):
class_ = super(Meta,mcl).__new__(mcl,*args,**kw)
mcl._classes.append(class_)
class_._instances = []
return class_
_classes = []

def factory():
class Class(object):
__metaclass__ = Meta
def __new__(cls,*args,**kw):
instance = super(Class,cls).__new__(cls,*args,**kw)
cls._instances.append(instance)
return instance
return Class
A = factory()
class B(A): pass ....
a = A()
b = B()
Meta._classes
A._instances
[ said:
B._instances
[<__main__.B object at 0xb7dbb0ec>]

So, you see that you can access all classes, their subclasses, and
instances from Meta.

Of course in a more elaborate version _classes and _instances should
store weak references, so that classes and instances can actually be
deleted. I also haven't explored under which circumstances this can
break ...

I can imagine different use cases for this, (though they certainly are
non-standard :)). I once contemplated the (toy-) implementation of a
frame-based knowledge representation system using Python's object
model, where one definitely needs classes to keep track of their
instances ...

Cheers,
Andreas
 
T

Thomas Heller

Karlo said:
Hi,

what's the best way to keep track of user-made subclasses, and instances of
those subclasses? I just need a pointer in a right direction... thanks.

New style classes have a __subclasses__ class method that shows the direct subclasses:

Python 2.4.4 (#71, Oct 18 2006, 08:34:43) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
No builtin mechanism for instances exists, afaik.

Thomas
 
P

Paul Rubin

Steven D'Aprano said:
Is there a problem with writing C like this?
class C(object):
def __init__(self):
logging.warn('Allocating resource ...')
self.__log = logging.warn
It works for me. Have I missed something?

I thought the OP wanted to the program to notice when subclasses were
created, not just instances of them. As Andreas Kraemer described,
you can do that with a metaclass.
 
M

Michele Simionato

Is there a problem with writing C like this?

class C(object):
def __init__(self):
logging.warn('Allocating resource ...')
self.__log = logging.warn
def __del__(self):
self.__log('De-allocating resource ...')
print 'THIS IS REACHED!'

It works for me. Have I missed something?

Another more common workaround is to use default arguments:

class C(object):
def __init__(self):
logging.warn('Allocating resource ...')
def __del__(self, warn=logging.warn):
warn('De-allocating resource ...')
print 'THIS IS REACHED!'

But, as you know, I want to remove __del__ because of the problem with
reference
cycles, not because of this little issue with the cleanup mechanism
(which BTW is shared
also by the weak references callback mechanism).

Michele Simionato
 
E

Erik Jones

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,

What about the following solution?

class Meta(type):
def __new__(mcl,*args,**kw):
class_ = super(Meta,mcl).__new__(mcl,*args,**kw)
mcl._classes.append(class_)
class_._instances = []
return class_
_classes = []

def factory():
class Class(object):
__metaclass__ = Meta
def __new__(cls,*args,**kw):
instance = super(Class,cls).__new__(cls,*args,**kw)
cls._instances.append(instance)
return instance
return Class
A = factory()
class B(A): pass ...
a = A()
b = B()
Meta._classes
[ said:
B._instances
[<__main__.B object at 0xb7dbb0ec>]

So, you see that you can access all classes, their subclasses, and
instances from Meta.

Of course in a more elaborate version _classes and _instances should
store weak references, so that classes and instances can actually be
deleted. I also haven't explored under which circumstances this can
break ...

I can imagine different use cases for this, (though they certainly are
non-standard :)). I once contemplated the (toy-) implementation of a
frame-based knowledge representation system using Python's object
model, where one definitely needs classes to keep track of their
instances ...

Another use case that I've run across is when defining model classes
using an ORM against a database that uses table inheritance
extensively with the result that the database has way more tables
than you'd actually want to manually maintain model classes/files for.

Erik Jones

Software Developer | Emma®
(e-mail address removed)
800.595.4401 or 615.292.5888
615.292.0777 (fax)

Emma helps organizations everywhere communicate & market in style.
Visit us online at http://www.myemma.com
 
B

Bruno Desthuilliers

George Sakkis a écrit :
(snip)
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:

Actually, you don't even need that restriction - just move the tracking
code from __init__ to __new__.
from collections import deque
from weakref import WeakKeyDictionary

class InstanceTracker(object):
def __new__(cls, *args, **kw):
try:
all = cls.__dict__['__instances__']
except KeyError:
cls.__instances__ = all = WeakKeyDictionary()
self = super(InstanceTracker, self).__new__(cls)
all[self] = None
return self

(NB : untested)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top