关于python:有没有一种简单、优雅的方法来定义singletons?

关于python:有没有一种简单、优雅的方法来定义singletons?

Is there a simple, elegant way to define singletons?

本问题已经有最佳答案,请猛点这里访问。

在Python中似乎有许多定义单例的方法。对于堆栈溢出是否有共识?


我不认为这是真正的需要,因为一个具有函数(而不是类)的模块可以作为一个单例来使用。它的所有变量都将绑定到模块,模块无论如何都不能重复实例化。

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


这是我自己的单例实现。你所要做的就是修饰这个类;为了得到单例,你必须使用Instance方法。下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
@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

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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)

您可以这样重写__new__方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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"

在python中实现singleton的一个稍有不同的方法是由alex martelli(Google员工和python genius)开发的borg模式。

1
2
3
4
class Borg:
    __shared_state = {}
    def __init__(self):
        self.__dict__ = self.__shared_state

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


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

1
2
3
4
5
6
7
8
9
10
11
12
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

请参阅PEP318中的此实现,使用修饰器实现单例模式:

1
2
3
4
5
6
7
8
9
10
11
def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    ...

正如公认的答案所说,最惯用的方法就是只使用一个模块。

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

1
2
3
4
5
6
7
8
9
10
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

有关__new__的更多详细信息,请参见python数据模型。

例子:

1
2
3
4
5
6
7
8
@singleton
class Duck(object):
    pass

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

笔记:

  • 为此,必须使用新的样式类(从object派生)。

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

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


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

    1
    2
    3
    4
    5
    6
    _data_controller = None
    def GetDataController():
        global _data_controller
        if _data_controller is None:
            _data_controller = DataController()
        return _data_controller

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


    有一次我用python编写了一个singleton,我使用了一个类,其中所有成员函数都有classmethod修饰符。

    1
    2
    3
    4
    5
    6
    class foo:
      x = 1

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


    python文档确实包括以下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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

    我可能会把它改写成这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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

    扩展这一点应该比较干净:

    1
    2
    3
    4
    5
    class Bus(Singleton):
        def init(self, label=None, *args, **kwds):
            self.label = label
            self.channels = [Channel("system"), Channel("app")]
            ...

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

    • 单身是病态的骗子
    • 单身汉都去哪儿了?
    • 单子的根本原因

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def singleton(cls):
        instances = {}
        def getinstance():
            if cls not in instances:
                instances[cls] = cls()
            return instances[cls]
        return getinstance

    @singleton
    class MyClass:
        ...

    下面是彼得·诺维格的python iaq中的一个例子,如何在python中使用singleton模式?(您应该使用浏览器的搜索功能来查找此问题,没有直接链接,抱歉)

    布鲁斯·埃克尔在他的《用Python思考》一书中也有另一个例子(同样也没有直接链接到代码)。


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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

    或者,如果在模块首次导入时实例化没有问题:

    1
    2
    3
    4
    class NothingSpecial:
        pass

    THE_ONE_AND_ONLY = NothingSpecial()

    这样,您就可以针对没有副作用的新实例编写测试,并且不需要用全局语句散布模块,如果需要,您可以在将来派生变量。


    好吧,我知道,单身汉可以是好人也可以是坏人。这是我的实现,我只是扩展了一个经典的方法来在内部引入一个缓存,并生成许多不同类型的实例,或者许多相同类型的实例,但参数不同。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    # 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>}

    每个对象都带有单例缓存…这可能是邪恶的,但对某些人来说效果很好。)


    由于对Python比较陌生,我不知道最常见的习惯用法是什么,但是我能想到的最简单的一点就是使用模块而不是类。类上的实例方法会变成模块中的函数,任何数据都会变成模块中的变量,而不是类的成员。我怀疑这是解决人们使用单胎技术解决问题的方法。

    如果您真的想要一个singleton类,那么对于"python singleton",在第一次点击谷歌时就有一个合理的实现描述,具体来说:

    1
    2
    3
    4
    5
    6
    class Singleton:
        __single = None
        def __init__( self ):
            if Singleton.__single:
                raise Singleton.__single
            Singleton.__single = self

    这似乎起到了作用。


    由activestate提供的python实现的singleton模式。

    看起来诀窍是将应该只有一个实例的类放入另一个类中。


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

    1
    2
    3
    4
    5
    6
    7
    8
    def getSystemContext(contextObjList=[]):
        if len( contextObjList ) == 0:
            contextObjList.append( Context() )
            pass
        return contextObjList[0]

    class Context(object):
        # Anything you want here

    辛格尔顿的同父异母兄弟

    我完全同意Staale的观点,我在这里留下了一个创建独生子女同父异母兄弟的样本:

    1
    2
    3
    class void:pass
    a = void();
    a.__class__ = Singleton

    a现在将报告为与Singleton属于同一类,即使它看起来不像。因此,使用复杂类的单子最终取决于我们对它们没有太多的干扰。

    正因为如此,我们可以有同样的效果,使用更简单的东西,比如变量或模块。不过,如果为了清晰起见而使用类,并且因为在Python中,类是一个对象,所以我们已经拥有了该对象(不是和实例,但它的作用与之类似)。

    1
    2
    class Singleton:
        def __new__(cls): raise AssertionError # Singletons can't have instances

    在这里,如果我们尝试创建一个实例,就会有一个很好的断言错误,并且我们可以存储派生静态成员,并在运行时对它们进行更改(我喜欢Python)。这个对象和其他大约一半的兄弟一样好(如果您愿意,您仍然可以创建它们),但是由于简单性,它的运行速度会更快。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Singleton(object[,...]):

        staticVar1 = None
        staticVar2 = None

        def __init__(self):
            if self.__class__.staticVar1==None :
                # create class instance variable for instantiation of class
                # assign class instance variable values to class static variables
            else:
                # assign class static variable values to class instance variables

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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类上的静态方法将不起作用),那么这种折衷方法会起作用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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)


    推荐阅读