class that keeps track of instances

G

Guest

Hello all,

I'd like some advices from more experienced python users. I want to
have a class in my python application that does not allow multiple
instance with same "name".

I want to have a class (call it kls) that behave at least following way:

1) New instance has to have a property called 'name'
2) When instance is attemped to created, e.g., x=kls(name='myname'), and
there already exists an instance with obj.name =='myname', that
pre-existing instance is returned, instead of making new one.
3) A class property 'all' for class gives me a list of all the
instances. So kls.all lets me iterates through all instances.
4) When all the hard-link to an instance is deleted, the instance should
be deleted, just like an instance from any regular class does.

My question is if i can find metaclass or something that allows me to
create such class easily. I tried to search such thing on internet, but
I even don't know how to call this kind of thing. It is in a sense like
singleton, but less restrictive.

Assuming that I have to write it on my own, what should I do? I tried
to implement it using weakref.WeakValueDictionary and metaclass, but
instance doesn't disappear when I think it should disappear. I am also
wondering if it is easier to keeping {name:id(obj)} would be a better
solution.

Any other suggestions are very much appreciated as well.
 
H

Hrvoje Niksic

1) New instance has to have a property called 'name'
2) When instance is attemped to created, e.g., x=kls(name='myname'), and
there already exists an instance with obj.name =='myname', that
pre-existing instance is returned, instead of making new one.
3) A class property 'all' for class gives me a list of all the
instances. So kls.all lets me iterates through all instances.
4) When all the hard-link to an instance is deleted, the instance should
be deleted, just like an instance from any regular class does.

class Meta(type):
all = property(lambda type: type.cache.values())

class kls(object):
__metaclass__ = Meta
cache = weakref.WeakValueDictionary()
def __new__(cls, name):
if name in kls.cache:
return kls.cache[name]
self = object.__new__(cls)
self.name = name
kls.cache[name] = self
return self
x = kls(name='foo')
x
x is kls(name='foo') True
x is kls(name='bar') False
print kls.all # only one instance, 'bar' was short-lived
[ said:
x = 'somethingelse'
print kls.all
[]

Assuming that I have to write it on my own, what should I do? I
tried to implement it using weakref.WeakValueDictionary and
metaclass, but instance doesn't disappear when I think it should
disappear. I am also wondering if it is easier to keeping
{name:id(obj)} would be a better solution.

The problem is that, given just an ID, you have no way to get a hold
of the actual object.
 
G

Gabriel Genellina

I'd like some advices from more experienced python users. I want to
have a class in my python application that does not allow multiple
instance with same "name".

I want to have a class (call it kls) that behave at least following way:

1) New instance has to have a property called 'name'
2) When instance is attemped to created, e.g., x=kls(name='myname'), and
there already exists an instance with obj.name =='myname', that
pre-existing instance is returned, instead of making new one.

For all of this I would use the __new__ method.
3) A class property 'all' for class gives me a list of all the
instances. So kls.all lets me iterates through all instances.
4) When all the hard-link to an instance is deleted, the instance should
be deleted, just like an instance from any regular class does.

I'd store a WeakValueDictionary using the name as a key. Instead of a
property 'all', I'd use a method 'get_all_instances()' that should
call values() on the weak dictionary.
My question is if i can find metaclass or something that allows me to
create such class easily. I tried to search such thing on internet, but
I even don't know how to call this kind of thing. It is in a sense like
singleton, but less restrictive.

Have you tried the Python Cookbook?
Assuming that I have to write it on my own, what should I do? I tried
to implement it using weakref.WeakValueDictionary and metaclass, but
instance doesn't disappear when I think it should disappear. I am also
wondering if it is easier to keeping {name:id(obj)} would be a better
solution.

A WeakValueDictionary should work. If the instance is not deleted when
you expect, maybe there are other references somewhere, or the garbage
collector didn't run yet.

Ok, finally I wrote an example:

py> from weakref import WeakValueDictionary
py>
py> class OneOfAKind(object):
.... _instances = WeakValueDictionary()
.... def __new__(cls, name):
.... inst = cls._instances.get(name, None)
.... if inst is None:
.... inst = cls._instances[name] = super(OneOfAKind,
cls).__new__(cls
)
.... inst.name = name
.... return inst
.... @classmethod
.... def get_all_instances(cls):
.... return cls._instances.values()
.... __str__ = __repr__ = lambda self: '%s(%r)' %
(self.__class__.__name__, s
elf.name)
....
py> a = OneOfAKind('A')
py> b = OneOfAKind('A')
py> assert b is a
py> c = OneOfAKind('C')
py> assert c is not a
py> print OneOfAKind.get_all_instances()
[OneOfAKind('A'), OneOfAKind('C')]
py> del c
py> import gc
py> gc.collect()
17
py> print OneOfAKind.get_all_instances()
[OneOfAKind('A')]
py> del a
py> del b
py> gc.collect()
0
py> print OneOfAKind.get_all_instances()
[]
py>
 
G

Guest

I want to have a class in my python application that does not allow
multiple instance with same "name".

Thank you very much for very quick and precise answers to my questions!
input for garbage collector and id are appreciated as well. I head to
bookstore for the cookbook (O'reily's, right?). i thought it was too
cryptic but maybe time for met to revisit the book.
 

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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top