Singleton

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Singleton

Marco Pesenti Gritti
Hi,

we should probably settle on a consistent implementation for singletons.

This is what we have in the ps:

_ps = None
def get_instance():
        global _ps
        if not _ps:
                _ps = PresenceService()
        return _ps

and PresenceService.get_instance() to get it.

In the icon cache:

class IconCache(gobject.GObject):
    __metaclass__ = GObjectSingletonMeta

using this from sugar.util

class GObjectSingletonMeta(gobject.GObjectMeta):
    """GObject Singleton Metaclass"""

    def __init__(klass, name, bases, dict):
        gobject.GObjectMeta.__init__(klass, name, bases, dict)
        klass.__instance = None

    def __call__(klass, *args, **kwargs):
        if klass.__instance is None:
            klass.__instance = gobject.GObjectMeta.__call__(klass,
*args, **kwargs)
        return klass.__instance

and you can use the normal constructor.

Thoughts?

Marco
Reply | Threaded
Open this post in threaded view
|

Singleton

Ivan Krstić-2
Marco Pesenti Gritti wrote:
> we should probably settle on a consistent implementation for singletons.

The recommended way of doing this in Python is the Borg pattern:

 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531

--
Ivan Krsti? <[hidden email]> | GPG: 0x147C722D
Reply | Threaded
Open this post in threaded view
|

Re: Singleton

Ian Bicking
In reply to this post by Marco Pesenti Gritti
Marco Pesenti Gritti <mpg <at> redhat.com> writes:

> Hi,
>
> we should probably settle on a consistent implementation for singletons.
>
> This is what we have in the ps:
>
> _ps = None
> def get_instance():
>         global _ps
>         if not _ps:
>                 _ps = PresenceService()
>         return _ps
>
> and PresenceService.get_instance() to get it.

If using this pattern, you should is "if _ps is None" and PresenceService
should be named _PresenceService (because it is private).  If you don't need
to instantiate the object lazily, you should do:

  presence_service = _PresenceService()

at the module level, and then presence_service is the singleton (and you
won't instantiate other instances unless you go out of your way to get the
private class.

If you really want lazy instantiation, I prefer a factory function like
get_instance().

> In the icon cache:
>
> class IconCache(gobject.GObject):
>     __metaclass__ = GObjectSingletonMeta
>
> using this from sugar.util
>
> class GObjectSingletonMeta(gobject.GObjectMeta):
>     """GObject Singleton Metaclass"""
>
>     def __init__(klass, name, bases, dict):
>         gobject.GObjectMeta.__init__(klass, name, bases, dict)
>         klass.__instance = None
>
>     def __call__(klass, *args, **kwargs):
>         if klass.__instance is None:
>             klass.__instance = gobject.GObjectMeta.__call__(klass,
> *args, **kwargs)
>         return klass.__instance
>
> and you can use the normal constructor.

The arguments get ignored if the singleton has already been created; that's
no good.  Either there should be zero arguments, or it shouldn't be a
singleton.  

Incidentally, you can also make a class a singleton (or instances unique
based on the constructor parameters) by overriding __new__ (instead of the
metaclass's __call__), though I don't know if one is better than the other.  
The metaclass is probably better, because __new__ has some quirky behavior with
respect to __init__.

I personally don't care for the Borg pattern; module-level instantiation is
usually the right thing to do, and a factory function is very easy to
understand otherwise.  Also, instances with a shared __dict__ are a little
crazy.  Mostly singleton patterns involve over-design IMHO -- there's several
situations that call for different implementations, and all they have in
common is that in some languages those different things are all implemented
with singletons, even though that might not be appropriate in Python.

  Ian