Is there a simple, elegant way to define singleton

2018-12-31 04:36发布

This question already has an answer here:

There seem to be many ways to define singletons in Python. Is there a consensus opinion on Stack Overflow?

22条回答
倾城一夜雪
2楼-- · 2018-12-31 05:18

As the accepted answer says, the most idiomatic way is to just use a module.

With that in mind, here's a proof of concept:

def singleton(cls):
    obj = cls()
    # Always return the same object
    cls.__new__ = staticmethod(lambda cls: obj)
    # Disable __init__
    try:
        del cls.__init__
    except AttributeError:
        pass
    return cls

See the Python data model for more details on __new__.

Example:

@singleton
class Duck(object):
    pass

if Duck() is Duck():
    print "It works!"
else:
    print "It doesn't work!"

Notes:

  1. You have to use new-style classes (derive from object) for this.

  2. The singleton is initialized when it is defined, rather than the first time it's used.

  3. This is just a toy example. I've never actually used this in production code, and don't plan to.

查看更多
浮光初槿花落
3楼-- · 2018-12-31 05:18

In cases where you don't want the metaclass-based solution above, and you don't like the simple function decorator-based approach (e.g. because in that case static methods on the singleton class won't work), this compromise works:

class singleton(object):
  """Singleton decorator."""

  def __init__(self, cls):
      self.__dict__['cls'] = cls

  instances = {}

  def __call__(self):
      if self.cls not in self.instances:
          self.instances[self.cls] = self.cls()
      return self.instances[self.cls]

  def __getattr__(self, attr):
      return getattr(self.__dict__['cls'], attr)

  def __setattr__(self, attr, value):
      return setattr(self.__dict__['cls'], attr, value)
查看更多
美炸的是我
4楼-- · 2018-12-31 05:19

I don't really see the need, as a module with functions (and not a class) would serve well as a singleton. All its variables would be bound to the module, which could not be instantiated repeatedly anyway.

If you do wish to use a class, there is no way of creating private classes or private constructors in Python, so you can't protect against multiple instantiations, other than just via convention in use of your API. I would still just put methods in a module, and consider the module as the singleton.

查看更多
与君花间醉酒
5楼-- · 2018-12-31 05:19

Here is an example from Peter Norvig's Python IAQ How do I do the Singleton Pattern in Python? (You should use search feature of your browser to find this question, there is no direct link, sorry)

Also Bruce Eckel has another example in his book Thinking in Python (again there is no direct link to the code)

查看更多
公子世无双
6楼-- · 2018-12-31 05:20

You can override the __new__ method like this:

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(
                                cls, *args, **kwargs)
        return cls._instance


if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()
    if (id(s1) == id(s2)):
        print "Same"
    else:
        print "Different"
查看更多
梦该遗忘
7楼-- · 2018-12-31 05:20

Creating a singleton decorator (aka an annotation) is an elegant way if you want to decorate (annotate) classes going forward. Then you just put @singleton before your class definition.

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    ...
查看更多
登录 后发表回答