Python 有没有一种简单、优雅的方式来定义单身汉?

Python 有没有一种简单、优雅的方式来定义单身汉?,python,design-patterns,singleton,Python,Design Patterns,Singleton,在Python中,似乎有很多方法可以定义。对StackOverflow有一致的看法吗?对于Python来说,这是一个相对较新的概念,我不确定最常见的习惯用法是什么,但我能想到的最简单的方法是使用模块而不是类。类上的实例方法只会成为模块中的函数,任何数据只会成为模块中的变量,而不是类的成员。我怀疑这是解决人们使用单例解决的问题类型的一种pythonic方法 如果您真的想要一个singleton类,那么在“Python singleton”中有一个合理的实现,具体如下: class Singleto

在Python中,似乎有很多方法可以定义。对StackOverflow有一致的看法吗?

对于Python来说,这是一个相对较新的概念,我不确定最常见的习惯用法是什么,但我能想到的最简单的方法是使用模块而不是类。类上的实例方法只会成为模块中的函数,任何数据只会成为模块中的变量,而不是类的成员。我怀疑这是解决人们使用单例解决的问题类型的一种pythonic方法

如果您真的想要一个singleton类,那么在“Python singleton”中有一个合理的实现,具体如下:

class Singleton:
    __single = None
    def __init__( self ):
        if Singleton.__single:
            raise Singleton.__single
        Singleton.__single = self

这似乎很管用。

我真的不认为有必要,因为带有函数(而不是类)的模块可以很好地充当单例。它的所有变量都将绑定到模块,模块无论如何都不能重复实例化


如果您确实希望使用一个类,那么在Python中无法创建私有类或私有构造函数,因此除了通过API中的约定之外,您无法防止多次实例化。我仍然将方法放在一个模块中,并将该模块视为单体。

< P>在Python中实现单体的稍微不同的方法是Alex Martelli(谷歌Engin和Python天才)。


因此,与其强制所有实例具有相同的标识,它们共享状态。

模块方法效果良好。如果我绝对需要一个单例,我更喜欢元类方法

class Singleton(type):
    def __init__(cls, name, bases, dict):
        super(Singleton, cls).__init__(name, bases, dict)
        cls.instance = None 

    def __call__(cls,*args,**kw):
        if cls.instance is None:
            cls.instance = super(Singleton, cls).__call__(*args, **kw)
        return cls.instance

class MyClass(object):
    __metaclass__ = Singleton

有一次我用Python编写了一个单例,我使用了一个类,其中所有成员函数都有classmethoddecorator

class Foo:
    x = 1
  
    @classmethod
    def increment(cls, y=1):
        cls.x += y
由州政府提供


看起来诀窍在于将本应只有一个实例的类放在另一个类中。

Google测试博客上也有一些有趣的文章,讨论了为什么singleton是/可能是坏的,是一种反模式:


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

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

      它不是优雅的,因为它是一个完整的六行。但是我所有的单身汉都使用这种模式,而且它至少非常明确(这是pythonic)。

      您可以像这样覆盖
      \uuuuuuu new\uuuu
      方法:

      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"
      

      请参阅中的实现,使用装饰器实现singleton模式:

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

      我认为,强迫一个类或一个实例成为一个单例是过分的。就我个人而言,我喜欢定义一个普通的可实例化类、一个半私有引用和一个简单的工厂函数

      class NothingSpecial:
          pass
      
      _the_one_and_only = None
      
      def TheOneAndOnly():
          global _the_one_and_only
          if not _the_one_and_only:
              _the_one_and_only = NothingSpecial()
          return _the_one_and_only
      
      或者,如果首次导入模块时实例化没有问题:

      class NothingSpecial:
          pass
      
      THE_ONE_AND_ONLY = NothingSpecial()
      

      这样,您就可以针对新实例编写测试,而不会产生副作用,并且不需要向模块中添加全局语句,如果需要,您可以在将来派生变体。

      以下是我自己的单例实现。你所要做的就是装饰教室;要获得单例,必须使用
      实例
      方法。下面是一个例子:

      @Singleton
      class Foo:
         def __init__(self):
             print 'Foo created'
      
      f = Foo() # Error, this isn't how you get the instance of a singleton
      
      f = Foo.instance() # Good. Being explicit is in line with the Python Zen
      g = Foo.instance() # Returns already created instance
      
      print f is g # True
      
      下面是代码:

      class Singleton:
          """
          A non-thread-safe helper class to ease implementing singletons.
          This should be used as a decorator -- not a metaclass -- to the
          class that should be a singleton.
      
          The decorated class can define one `__init__` function that
          takes only the `self` argument. Also, the decorated class cannot be
          inherited from. Other than that, there are no restrictions that apply
          to the decorated class.
      
          To get the singleton instance, use the `instance` method. Trying
          to use `__call__` will result in a `TypeError` being raised.
      
          """
      
          def __init__(self, decorated):
              self._decorated = decorated
      
          def instance(self):
              """
              Returns the singleton instance. Upon its first call, it creates a
              new instance of the decorated class and calls its `__init__` method.
              On all subsequent calls, the already created instance is returned.
      
              """
              try:
                  return self._instance
              except AttributeError:
                  self._instance = self._decorated()
                  return self._instance
      
          def __call__(self):
              raise TypeError('Singletons must be accessed through `instance()`.')
      
          def __instancecheck__(self, inst):
              return isinstance(inst, self._decorated)
      

      如果您不想要上述基于元类的解决方案,并且不喜欢简单的基于函数装饰器的方法(例如,因为在这种情况下,singleton类上的静态方法将不起作用),这种折衷方法可以起作用:

      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)
      

      我的简单解决方案是基于函数参数的默认值

      def getSystemContext(contextObjList=[]):
          if len( contextObjList ) == 0:
              contextObjList.append( Context() )
              pass
          return contextObjList[0]
      
      class Context(object):
          # Anything you want here
      

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

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

      好吧,我知道单身男女可能是好的也可能是坏的。这是我的实现,我只是扩展了一种经典方法,在其中引入缓存,并生成许多不同类型的实例,或者许多相同类型的实例,但参数不同

      我称之为Singleton_group,因为它将相似的实例分组在一起,并防止创建具有相同参数的同一类的对象:

      # Peppelinux's cached singleton
      class Singleton_group(object):
          __instances_args_dict = {}
          def __new__(cls, *args, **kwargs):
              if not cls.__instances_args_dict.get((cls.__name__, args, str(kwargs))):
                  cls.__instances_args_dict[(cls.__name__, args, str(kwargs))] = super(Singleton_group, cls).__new__(cls, *args, **kwargs)
              return cls.__instances_args_dict.get((cls.__name__, args, str(kwargs)))
      
      
      # It's a dummy real world use example:
      class test(Singleton_group):
          def __init__(self, salute):
              self.salute = salute
      
      a = test('bye')
      b = test('hi')
      c = test('bye')
      d = test('hi')
      e = test('goodbye')
      f = test('goodbye')
      
      id(a)
      3070148780L
      
      id(b)
      3070148908L
      
      id(c)
      3070148780L
      
      b == d
      True
      
      
      b._Singleton_group__instances_args_dict
      
      {('test', ('bye',), '{}'): <__main__.test object at 0xb6fec0ac>,
       ('test', ('goodbye',), '{}'): <__main__.test object at 0xb6fec32c>,
       ('test', ('hi',), '{}'): <__main__.test object at 0xb6fec12c>}
      
      Peppelinux的缓存单例 类单例组(对象): __实例参数dict={} 定义(cls,*ARG,**kwargs): 如果不是cls.\u实例\u参数\u指令获取((cls.\u名称\u参数,str(kwargs)): cls.\uuuuu实例\uu参数\uu dict[(cls.\uuuuuu名称,参数,str(kwargs))]=super(Singleton\u组,cls)。\uuuuu新参数(cls,*参数,**kwargs) 返回cls.\uuuuu实例\uu参数\u dict.get((cls.\uuuuuu name\uuuuuuu,args,str(kwargs))) #这是一个虚拟现实世界使用示例: 班级测试(单亲组): 定义初始(自我,敬礼): 自我敬礼 a=测试(‘再见’) b=测试('hi') c=测试(‘再见’) d=测试('hi') e=测试(‘再见’) f=测试(‘再见’) 身份证(a) 3070148780L 身份证(b) 3070148908L id(c) 3070148780L b==d 真的 b、 单例组实例参数 {('test',('bye',),'{}'):, (‘test’,(‘再见’,),‘{}’:, ('test',('hi',),'{}'):} 每个对象都携带单例缓存。。。这可能是邪恶的,但对某些人来说效果很好:)

      确实涵盖了这一点:

      class Singleton(object):
          def __new__(cls, *args, **kwds):
              it = cls.__dict__.get("__it__")
              if it is not None:
                  return it
              cls.__it__ = it = object.__new__(cls)
              it.init(*args, **kwds)
              return it
          def init(self, *args, **kwds):
              pass
      
      我可能会重写它,使其看起来更像这样:

      class Singleton(object):
          """Use to create a singleton"""
          def __new__(cls, *args, **kwds):
              """
              >>> s = Singleton()
              >>> p = Singleton()
              >>> id(s) == id(p)
              True
              """
              self = "__self__"
              if not hasattr(cls, self):
                  instance = object.__new__(cls)
                  instance.init(*args, **kwds)
                  setattr(cls, self, instance)
              return getattr(cls, self)
      
          def init(self, *args, **kwds):
              pass
      
      它应该相对干净,以扩展:

      class Bus(Singleton):
          def init(self, label=None, *args, **kwds):
              self.label = label
              self.channels = [Channel("system"), Channel("app")]
              ...
      
      正如上面所说,最惯用的方法就是使用模块

      考虑到这一点,这里有一个概念证明:

      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
      
      有关
      的更多详细信息,请参阅

      例如:

      @singleton
      class Duck(object):
          pass
      
      if Duck() is Duck():
          print "It works!"
      else:
          print "It doesn't work!"
      
      注:

    • 为此,必须使用新样式的类(派生自
      对象

    • 单例在定义时初始化,而不是在第一次使用时初始化

    • 这只是一个玩具的例子。我从未在生产代码中实际使用过它,也不打算这么做


    • 单身汉的同父异母兄弟

      我完全同意staale的观点,我在这里留下了c的样品
      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))
      
      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
      
      @singleton
      class Duck(object):
          pass
      
      if Duck() is Duck():
          print "It works!"
      else:
          print "It doesn't work!"
      
      class void:pass
      a = void();
      a.__class__ = Singleton
      
      class Singleton:
          def __new__(cls): raise AssertionError # Singletons can't have instances