classes

Michele Simionato mis6 at pitt.edu
Mon Jul 21 08:51:16 EDT 2003


Steven Taschuk <staschuk at telusplanet.net> wrote in message news:<mailman.1058723911.12956.python-list at python.org>...
> For the particular problem you're interested in -- singletons --
> here are a few approaches:
> 
> First, use __new__ trickery:
> 
>     _the_instance = None
>     class MySingleton(object):
>         def __new__(self):
>             global _the_instance
>             if _the_instance is None:
>                 _the_instance = object.__new__(self)
>             return _the_instance

Why are you using a global here and not something like


    class MySingleton(object):
        _the_instance = None
        def __new__(cls):
            if cls._the_instance is None:
                cls._the_instance = object.__new__(self)
            return cls._the_instance

?

> Example use:
> 
>     >>> x = MySingleton()
>     >>> y = MySingleton()
>     >>> x is y  # same object!
>     True
> 
> In this approach, users create instances of MySingleton as they
> would for any other class (rather than by calling a getInstance
> classmethod) -- that action just happens to return the same object
> always.
> 
> One gotcha with this approach can be observed by adding
> 
>     def __init__(self):
>         print 'running __init__ on instance %s' % id(self)
> 
> Then we see
> 
>     >>> x = MySingleton()
>  running __init__ on instance 1075795852
>     >>> y = MySingleton()
>  running __init__ on instance 1075795852
>     >>> x is y
>     True
> 
> As shown, each "instantiation" runs __init__ on the single
> instance again.  If you have initialization which should occur
> only when the single instance is actually created:
> 
>     _the_instance = None
>     class MySingleton(object):
>         def __new__(self):
>             global _the_instance
>             if _the_instance is None:
>                 _the_instance = object.__new__(self)
>                 _the_instance._my_init()
>             return _the_instance
>         def _my_init(self):
>             pass  # one-time initialization here
> 
> (Another possible issue with this approach arises when subclassing
> MySingleton.  Details left as an exercise.)
> 
> Second approach: Use a metaclass.  See
>     <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/102187>


Unfortunately, I see that this recipe is not very recommendable. I have
just submitted a fix which seems to work:

class Singleton(type):
    def __init__(cls,name,bases,dic):
        super(Singleton,cls).__init__(name,bases,dic)
        cls.instance=None
    def __call__(cls,*args,**kw):
        if cls.instance is None:
            cls.instance=super(Singleton,cls).__call__(*args,**kw)
        return cls.instance

Here is how it works under inheritance and avoids the problem with
calling __init__ twice:

class C:
    __metaclass__=Singleton
    def __init__(self):
        print "C: initializing ",self

class D(C):
    def __init__(self):
        print "D: initializing ",self

c1=C() # => C: initializing  <__main__.C object at 0x4031c0ac>
c2=C() # no output
d=D() # D: initializing  <__main__.D object at 0x4031c02c>
print c1 is c2 # => yes

 
> Third: forget about singletons and use a Borg.  See
>     <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531>
> (With Borgs, multiple instances may exist, but they share state.)
> 
> Fourth: rethink the idea that a database connection should be a
> singleton.  See
>     <http://c2.com/cgi/wiki?SingletonsAreEvil>
> and linked pages for discussion on the merits of singletons.


HTH,
                Michele




More information about the Python-list mailing list