class that keeps track of instances

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Mon Sep 17 19:08:07 EDT 2007


On 17 sep, 19:10, <yos... at ccwf.cc.utexas.edu> wrote:

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

--
Gabriel Genellina





More information about the Python-list mailing list