在Python中似乎有很多方法来定义单例对象。对Stack Overflow是否有一致的意见?


当前回答

如果你不想要上面的基于元类的解决方案,并且你不喜欢简单的基于函数装饰器的方法(例如,因为在这种情况下,单例类上的静态方法将不起作用),这种妥协是可行的:

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)

其他回答

如果你不想要上面的基于元类的解决方案,并且你不喜欢简单的基于函数装饰器的方法(例如,因为在这种情况下,单例类上的静态方法将不起作用),这种妥协是可行的:

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)

我对此非常不确定,但我的项目使用'惯例单例'(不是强制单例),也就是说,如果我有一个名为DataController的类,我在同一个模块中定义这个:

_data_controller = None
def GetDataController():
    global _data_controller
    if _data_controller is None:
        _data_controller = DataController()
    return _data_controller

它并不优雅,因为它足足有六行。但是我所有的单例都使用这个模式,而且它至少是非常显式的(这是python的)。

class Singeltone(type):
    instances = dict()

    def __call__(cls, *args, **kwargs):
        if cls.__name__ not in Singeltone.instances:            
            Singeltone.instances[cls.__name__] = type.__call__(cls, *args, **kwargs)
        return Singeltone.instances[cls.__name__]


class Test(object):
    __metaclass__ = Singeltone


inst0 = Test()
inst1 = Test()
print(id(inst1) == id(inst0))

如果你想继续装饰(注释)类,创建一个单例装饰器(又名注释)是一种优雅的方式。然后将@singleton放在类定义之前。

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

@singleton
class MyClass:
    ...

有一次我用Python写了一个单例,我使用了一个类,其中所有成员函数都有classmethod装饰器。

class Foo:
    x = 1
  
    @classmethod
    def increment(cls, y=1):
        cls.x += y