Singleton-like pattern

Pedro Werneck pedro.werneck at bol.com.br
Fri Aug 1 22:25:27 EDT 2003


On 1 Aug 2003, Bengt Richter wrote:

> >> class MultiSingleton(type):
>    class MultiSingleton(object):
> >>     def __call__(cls, *args, **kwds):
>        def __new__(cls, *args, **kwds):
> >>         cache = cls.__dict__.get('__cache__')
> >>         if cache is None:
> >>             cls.__cache__ = cache = {}
> >>         tag = str(args) + str(kwds)
>            tag = '%r%r'% (args, kwds)   # might be an alternative
> >>         if tag in cache:
> >>             return cache[tag]
> >>         obj = object.__new__(cls)
> >>         obj.__init__(*args, **kwds)
> >>         cache[tag] = obj
> >>         return obj

This is exactly what I did at first... I only changed it to a metaclass
because I was adding it to a module that already contain some other
metaclasses I use; I think it's more elegant as I said before... a
'quick and dirty' benchmark with the timeit module returned the
folowing results, and in this project I will be dealing with a database
of 7000+ items, this 20% bit may help a little:

__metaclass__:
[39.744094967842102, 40.455733060836792, 42.027853965759277]

__new__:
[47.914013981819153, 48.721022009849548, 49.430392026901245]


On 1 Aug 2003, Michele Simionato wrote:

> "memoize" is a possible name for this. Notice that the metaclass is a
> bit of overkill, you may well use a simple function for this job.

Hey... you wrote such a good article on python metaclasses and now don't
want people to use them ? :)

> Does (args,kw) work in general? IWT you could easily get something unhashable?
> IWT using a tuple of actual args may also be a bad idea since it would prevent callers'
> temp args from being garbage collected. I use repr to avoid that, maybe mistakenly?

> About the issue of finding a suitable key, in the same situation I have
> used the tuple (args,kw) as key. But me too I would like to ask if this is a
> good idea. What's the custom solution for getting a good key from
> a dictionary ?

Actually, (args, kw) doesn't work at all, even if you only get hashable
arguments... the 'kw' dict invalidate it as a key... besides, there's the
garbage collection problem, as Bengt Richter mentioned...

The "%r%r"%(args, kwds) works, as well as str((args, kwds))), but it
breaks if you get as argument an object with the default __repr__, as
the object id may be different, even if they are equal. Overriding __repr__
and returning a real representation avoids this problem.

Thanks for your time.

Pedro Werneck




More information about the Python-list mailing list