how to keep collection of existing instances and return one on instantiation

Peter Otten __peter__ at web.de
Wed Oct 5 13:03:33 EDT 2005


marduk wrote:

> What I *really* want is to keep a collection of all the Spam instances,
> and if i try to create a new Spam instance with the same contructor
> parameters, then return the existing Spam instance.  I thought new-style
> classes would do it:
> 
> class Spam(object):
>     cache = {}
>     def __new__(cls, x):
>         if cls.cache.has_key(x):
>             return cls.cache[x]

On cache misses you implicitly return None. But your __init__() method will
only be called if __new__() returns a Spam instance.

>     def __init__(self, x):
>         self.x = x
>         self.cache[x] = self
> 
> a = Spam('foo')
> b = Spam('foo')
> 
> Well, in this case a and b are identical... to None!  I assume this is
> because the test in __new__ fails so it returns None, I need to then
> create a new Spam.. but how do I do that without calling __new__ again?
> I can't call __init__ because there's no self...
> 
> So what is the best/preferred way to do this?

class Spam(object):
    cache = {}
    def __new__(cls, x):
        try:
            inst = cls.cache[x]
            print "from cache"
        except KeyError:
            cls.cache[x] = inst = object.__new__(cls)
            print "new instance"
        return inst # always return a Spam instance

    def __init__(self, x):
        # put one-off initialization into __new__() because __init__()
        # will be called with instances from cache hits, too.
        print "init", x

a = Spam('foo')
b = Spam('foo')

print a, b, a is b

Peter




More information about the Python-list mailing list