multi-Singleton-like using __new__

Arnaud Delobelle arnodel at googlemail.com
Fri Feb 8 12:42:12 EST 2008


On Feb 8, 4:44 pm, Freek Dijkstra <fr... at macfreek.nl> wrote:
> Is there a best practice on how to override __new__?
>
> I have a base class, RDFObject, which is instantiated using a unique
> identifier (a URI in this case). If an object with a given identifier
> already exists, I want to return the existing object, otherwise, I
> want to create a new object and add this new object to a cache. I'm
> not sure if there is a name for such a creature, but I've seen the
> name MultiSingleton in the archive.
>
> This is not so hard; this can be done by overriding __new__(), as long
> as I use a lock in case I want my code to be multi-threading
> compatible.
>
> import threading
> threadlock = threading.Lock()
>
> class RDFObject(object):
>     _cache = {}   # class variable is shared among all RDFObject
> instances
>     def __new__(cls, *args, **kargs):
>         assert len(args) >= 1
>         uri = args[0]
>         if uri not in cls._cache:
>             threadlock.acquire() # thread lock
>             obj = object.__new__(cls)
>             cls._cache[uri] = obj
>             threadlock.release() # thread unlock.
>         return cls._cache[uri]
>     def __init__(self, uri):
>         pass
>     # ...
>
> However, I have the following problem:
> The __init__-method is called every time you call RDFObject().

You need to override the __call__ method of the metaclass.  By default
is calls cls.__new__ then cls.__init__, e.g.:

class RDFObject(object):

    # This metaclass prevents __init__ from being automatically called
    # after __new__
    class __metaclass__(type):
        def __call__(cls, *args, **kwargs):
            return cls.__new__(cls, *args, **kwargs)
    # ...

HTH

--
Arnaud




More information about the Python-list mailing list