用Python创建一个单例

这个问题不是为了讨论是否需要单例设计模式、是否需要反模式或是否适合任何宗教战争,而是为了讨论如何以最符合Python风格的方式在Python中最好地实现该模式。在这个例子中,我定义"最python化"的意思是它遵循"最小惊奇原则"。

我有多个类,它们将成为单例(我的用例是针对日志记录器的,但这并不重要)。当我可以简单地继承或装饰时,我不希望在多个类中添加gumph。

最好的方法:

Method 1: A decorator

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

@singleton
class MyClass(BaseClass):
    pass

优点

装饰器在某种程度上是附加的,通常比多重继承更直观。

缺点

虽然使用MyClass()创建的对象是真正的单例对象,但是MyClass本身是一个函数,而不是一个类,因此不能从它调用类方法。同样对于m = MyClass(); n = MyClass(); o = type(n)();m == n && m != o && n != o方法2:基类

1
2
3
4
5
6
7
8
9
class Singleton(object):
    _instance = None
    def __new__(class_, *args, **kwargs):
        if not isinstance(class_._instance, class_):
            class_._instance = object.__new__(class_, *args, **kwargs)
        return class_._instance

class MyClass(Singleton, BaseClass):
    pass

优点

这是一个真正的班级

缺点

多重继承-啊!__new__可以在继承第二个基类时被覆盖吗?一个人必须想得比需要的更多。方法3:一个元类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

#Python2
class MyClass(BaseClass):
    __metaclass__ = Singleton

#Python3
class MyClass(BaseClass, metaclass=Singleton):
    pass

优点

这是一个真正的班级而覆盖继承将__metaclass__用于适当的目的(并使我意识到这一点)

缺点

有什么?方法4:decorator返回同名类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def singleton(class_):
    class class_w(class_):
        _instance = None
        def __new__(class_, *args, **kwargs):
            if class_w._instance is None:
                class_w._instance = super(class_w,
                                    class_).__new__(class_,
                                                    *args,
                                                    **kwargs)
                class_w._instance._sealed = False
            return class_w._instance
        def __init__(self, *args, **kwargs):
            if self._sealed:
                return
            super(class_w, self).__init__(*args, **kwargs)
            self._sealed = True
    class_w.__name__ = class_.__name__
    return class_w

@singleton
class MyClass(BaseClass):
    pass

优点

这是一个真正的班级而覆盖继承

缺点

创建每个新类不存在开销吗?这里,我们为每个希望创建单例的类创建两个类。虽然在我的情况下这是可以的,但我担心这可能无法扩展。当然,有一个争论的问题是,是否扩大这种模式太容易了……_sealed属性的意义是什么不能使用super()在基类上调用同名方法,因为它们会递归。这意味着您不能自定义__new__,也不能子类化需要您调用到__init__的类。


使用元类

我推荐方法#2,但是使用元类比使用基类更好。下面是一个示例实现:

1
2
3
4
5
6
7
8
9
class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class Logger(object):
    __metaclass__ = Singleton

或者在Python3

1
2
class Logger(metaclass=Singleton):
    pass

如果您想在每次调用该类时运行__init__,请添加

1
2
        else:
            cls._instances[cls].__init__(*args, **kwargs)

Singleton.__call__中的if语句。

关于元类的几句话。元类是类的类;也就是说,一个类是它的元类的一个实例。您可以在Python中找到带有type(obj)的对象的元类。普通的新样式类类型为type。上面代码中的Logger类型为class 'your_module.Singleton',就像Logger的(唯一)实例类型为class 'your_module.Logger'一样。当您使用Logger()调用logger时,Python首先询问LoggerSingleton的元类要做什么,从而允许抢占实例创建。这个过程与Python通过执行myclass.attribute引用类的属性时调用__getattr__来询问类要做什么是相同的。

元类本质上决定了类的定义是什么,以及如何实现这个定义。参见示例http://code.activestate.com/recipes/498149/,它使用元类在Python中重新创建c风格的struct。Python中元类的(具体)用例是什么?还提供了一些示例,它们通常似乎与声明式编程相关,尤其是在ORMs中使用的声明式编程。

在这种情况下,如果您使用您的方法#2,并且子类定义了一个__new__方法,那么每次您调用SubClassOfSingleton()时都会执行它——因为它负责调用返回存储实例的方法。对于元类,当创建唯一的实例时,它只会被调用一次。您需要自定义调用该类的含义,这由类的类型决定。

通常,使用元类来实现单例是有意义的。单例非常特殊,因为只创建一次,而元类是自定义类创建的方式。如果需要以其他方式定制单例类定义,使用元类可以提供更多的控制。

你单身不需要多重继承(因为元类不是一个基类),但对于使用多重继承的子类创建类的,您需要确保该单例类是第一/最左侧有一个元类重新定义__call__这是不太可能成为问题。实例dict不在实例的名称空间中,因此不会意外地覆盖它。

您还将听到singleton模式违反了"单一职责原则"——每个类应该只做一件事。这样,如果需要更改代码,您就不必担心弄乱代码所做的一件事,因为它们是独立的和封装的。元类实现通过了这个测试。元类负责执行模式,所创建的类和子类不需要知道它们是单例的。方法#1没有通过这个测试,正如您指出的"MyClass本身是一个函数,而不是一个类,因此您不能从它调用类方法。"

Python 2和3兼容版本

编写在Python2和python3中都能工作的东西需要使用稍微复杂一点的方案。由于元类通常是type类型的子类,所以可以使用一个类在运行时动态地创建一个中间基类,将其作为元类,然后将其用作公共Singleton基类的基类。解释起来比做起来难,如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
# works in Python 2 & 3
class _Singleton(type):
   """ A metaclass that creates a Singleton base class when called."""
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class Singleton(_Singleton('SingletonMeta', (object,), {})): pass

class Logger(Singleton):
    pass

具有讽刺意味的是,这种方法使用子类实现元类。一个可能的优势是,与纯元类不同,isinstance(inst, Singleton)将返回True

修正

在另一个主题上,您可能已经注意到了这一点,但是您最初的帖子中的基类实现是错误的。_instances需要在类上引用,您需要使用super()或递归,而__new__实际上是一个静态方法,您必须将类传递给它,而不是类方法,因为在调用该类时实际的类还没有创建。所有这些对于元类实现都是正确的。

1
2
3
4
5
6
7
8
9
10
11
class Singleton(object):
  _instances = {}
  def __new__(class_, *args, **kwargs):
    if class_ not in class_._instances:
        class_._instances[class_] = super(Singleton, class_).__new__(class_, *args, **kwargs)
    return class_._instances[class_]

class MyClass(Singleton):
  pass

c = MyClass()

装饰器返回一个类

我本来是写评论的,但是太长了,所以我在这里加上这个。方法#4比其他装饰器版本更好,但是它比单例所需的代码更多,而且它的功能也不太清楚。

主要问题源于类本身是基类。首先,如果一个类是一个几乎完全相同的类的子类,并且这个类的名称仅存在于它的__class__属性中,这难道不奇怪吗?这也意味着您不能在基类上用super()定义任何调用同名方法的方法,因为它们会递归。这意味着您的类不能自定义__new__,也不能从需要调用__init__的任何类派生。

何时使用单例模式

您的用例是希望使用单例的较好例子之一。你在其中一条评论中说:"对我来说,日志似乎一直是单身人士的自然选择。"你是绝对正确的。

当人们说单例对象不好时,最常见的原因是它们是隐含的共享状态。虽然全局变量和顶级模块导入是显式的共享状态,但是传递的其他对象通常是实例化的。这是一个很好的观点,但有两个例外。

第一个,也是在很多地方提到的一个,是当单例函数是常数时。使用全局常量,特别是枚举,是被广泛接受的,并且被认为是合理的,因为无论如何,没有一个用户可以为其他用户把它们搞砸。对于一个常量单例对象也是如此。

第二个异常(很少被提及)正好相反——当单例只是一个数据接收器,而不是数据源(直接或间接)时。这就是为什么日志记录器感觉像是单身人士的"自然"用法。由于不同的用户不会以其他用户关心的方式更改日志记录程序,所以并不存在真正的共享状态。这否定了反对单例模式的主要参数,并使它们成为一个合理的选择,因为它们易于用于任务。

以下引用自http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html:

Now, there is one kind of Singleton which is OK. That is a singleton where all of the reachable objects are immutable. If all objects are immutable than Singleton has no global state, as everything is constant. But it is so easy to turn this kind of singleton into mutable one, it is very slippery slope. Therefore, I am against these Singletons too, not because they are bad, but because it is very easy for them to go bad. (As a side note Java enumeration are just these kind of singletons. As long as you don't put state into your enumeration you are OK, so please don't.)

The other kind of Singletons, which are semi-acceptable are those which don't effect the execution of your code, They have no"side effects". Logging is perfect example. It is loaded with Singletons and global state. It is acceptable (as in it will not hurt you) because your application does not behave any different whether or not a given logger is enabled. The information here flows one way: From your application into the logger. Even thought loggers are global state since no information flows from loggers into your application, loggers are acceptable. You should still inject your logger if you want your test to assert that something is getting logged, but in general Loggers are not harmful despite being full of state.


1
2
3
4
class Foo(object):
     pass

some_global_variable = Foo()

模块只导入一次,其他的都是多余的。不要使用单例,也不要使用全局变量。


使用一个模块。它只导入一次。在其中定义一些全局变量——它们将是单例的"属性"。添加一些函数——单例的"方法"。


您可能永远都不需要Python中的单例。只要在一个模块中定义所有的数据和函数,就有了一个事实上的单例。

如果你真的必须有一个单例类,那么我会选择:

1
2
3
4
5
class My_Singleton(object):
    def foo(self):
        pass

my_singleton = My_Singleton()

使用方法:

1
2
from mysingleton import my_singleton
my_singleton.foo()

其中mysingleton.py是My_Singleton定义的文件名。这是因为在第一次导入文件之后,Python不会重新执行代码。


下面是给你的一句话:

1
singleton = lambda c: c()

你可以这样使用:

1
2
3
4
5
6
@singleton
class wat(object):
    def __init__(self): self.x = 1
    def get_x(self): return self.x

assert wat.get_x() == 1

对象被急切地实例化。这可能是你想要的,也可能不是。


是否有一种简单、优雅的方法来定义Python中的单例?有几个解决方案。

我强烈建议观看Alex Martelli关于python设计模式的讲座:第1部分和第2部分。特别是在第1部分中,他讨论了单例/共享状态对象。


下面是我自己的singletons实现。你所要做的就是装饰教室;要获得单例,您必须使用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
38
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. 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.

    Limitations: The decorated class cannot be inherited from.

   """


    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)


方法3看起来非常简洁,但是如果你想让你的程序同时运行在python2和python3中,它就不起作用了。甚至用Python版本的测试来保护单独的变量也失败了,因为python3版本在python2中给出了一个语法错误。

感谢Mike Watkins: http://mikewatkins.ca/2008/11/29/python2-3-metaclass/。如果你想让程序在python2和python3中都能运行,你需要做以下事情:

1
2
3
4
5
6
7
8
9
10
11
class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

MC = Singleton('MC', (object), {})

class MyClass(MC):
    pass    # Code for the class implementation

我假定赋值中的"object"需要替换为"BaseClass",但是我没有尝试过(我已经尝试过代码,如图所示)。


之前的答案是正确的,但是我不同意方法1"MyClass本身是一个函数,而不是一个类,所以您不能调用类方法"这句话。参见下面的例子,在MyClass中,这个方法被多次调用,MyClass用单例标记装饰。

另外,请注意,这与发布的一些答案非常相似,并且是基于python文档的,但是它略有不同,因为类和函数的设计方式是可以接收1或0个参数,而且仍然是单例的。

enter image description here下面是您可以多次调用singleton方法的证明,并显示仍然使用该类的一个实例,并且没有创建新对象。

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
#/usr/bin/env python

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

@singleton
class MyClass:
    def __init__(self,count=None):
        print("print argument if any exists",count)

    def test(self, counter):
        # time.sleep(1000)
        print("-->",counter)
        return counter

### create two objects to see if we get a singleton behavior !
a = MyClass(10000)
a.test(1)
b = MyClass()
b.test(2)
if a != b:
    print("this is not a singleton")

#lets makesure it's still is the same object
if a!=b:
    print("error")

因为theheadofabroom(发布问题的人)给了一些反馈关于他最初的问题然后我去从事一个新的解决方案基于他的反馈(我还保持以前的答案,因为我认为它可能有用一些,尽管它不是100% heheadofabroom到底是什么要求)。以下是最新的答案:

enter image description here

以下是复制和粘贴代码:)

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
#/usr/bin/env python
from functools import wraps

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

def add_function(cls):
    def outer_decorate_it(somefunction):
        @wraps(somefunction)
        def wrapper( *args, **kwargs):
            return somefunction(*args, **kwargs)
        setattr(cls, somefunction.__name__, wrapper)
        return somefunction
    return outer_decorate_it

@singleton
class MyClass():
    def __init__(self,count=None):
        print("print argument if any exists",count)

@add_function(MyClass)
def testit():
    print("It's me the function from the class")


MyClass.testit()


这个怎么样:

1
2
3
4
5
def singleton(cls):
    instance=cls()
    cls.__new__ = cls.__call__= lambda cls: instance
    cls.__init__ = lambda self: None
    return instance

在应该是单例的类上使用它作为装饰器。是这样的:

1
2
3
@singleton
class MySingleton:
    #....

这类似于另一个答案中的singleton = lambda c: c()装饰器。与其他解决方案一样,惟一的实例具有类的名称(MySingleton)。但是,使用这个解决方案,您仍然可以通过执行MySingleton()从类"创建"实例(实际上获取惟一的实例)。它还通过执行type(MySingleton)()防止创建其他实例(该操作也返回相同的实例)。


那么,除了同意python关于拥有模块级全局的一般建议外,下面的建议如何:

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
def singleton(class_):
    class class_w(class_):
        _instance = None
        def __new__(class2, *args, **kwargs):
            if class_w._instance is None:
                class_w._instance = super(class_w, class2).__new__(class2, *args, **kwargs)
                class_w._instance._sealed = False
            return class_w._instance
        def __init__(self, *args, **kwargs):
            if self._sealed:
                return
            super(class_w, self).__init__(*args, **kwargs)
            self._sealed = True
    class_w.__name__ = class_.__name__
    return class_w

@singleton
class MyClass(object):
    def __init__(self, text):
        print text
    @classmethod
    def name(class_):
        print class_.__name__

x = MyClass(111)
x.name()
y = MyClass(222)
print id(x) == id(y)

输出是:

1
2
3
111     # the __init__ is called only on the 1st time
MyClass # the __name__ is preserved
True    # this is actually the same instance


代码基于Tolli的答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#decorator, modyfies new_cls
def _singleton(new_cls):
    instance = new_cls()                                              #2
    def new(cls):
        if isinstance(instance, cls):                                 #4
            return instance
        else:
            raise TypeError("I can only return instance of {}, caller wanted {}".format(new_cls, cls))
    new_cls.__new__  = new                                            #3
    new_cls.__init__ = lambda self: None                              #5
    return new_cls


#decorator, creates new class
def singleton(cls):
    new_cls = type('singleton({})'.format(cls.__name__), (cls,), {} ) #1
    return _singleton(new_cls)


#metaclass
def meta_singleton(name, bases, attrs):
    new_cls = type(name, bases, attrs)                                #1
    return _singleton(new_cls)

解释:

创建新类,从给定的cls继承(它不会修改cls,以防有人想要例如singleton(list))

创建实例。在覆盖__new__之前,它是如此简单。

现在,当我们轻松创建实例时,使用刚才定义的方法覆盖__new__

函数只在调用者期望的时候返回instance,否则将引发TypeError。当有人试图从修饰类继承时,不满足此条件。

If __new__() returns an instance of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to __new__().

instance已经初始化,因此函数用不执行任何操作的函数替换__init__

看到它在网上工作


这与fab的答案有点相似,但并不完全相同。

单例契约不要求我们能够多次调用构造函数。作为一个单例应该只创建一次,而不是只创建一次?"欺骗"构造函数可能会损害可读性。

所以我的建议是:

1
2
3
4
5
6
7
8
9
10
11
12
class Elvis():
    def __init__(self):
        if hasattr(self.__class__, 'instance'):
            raise Exception()
        self.__class__.instance = self
        # initialisation code...

    @staticmethod
    def the():
        if hasattr(Elvis, 'instance'):
            return Elvis.instance
        return Elvis()

这并不排除使用构造函数或字段instance由用户代码:

1
if Elvis() is King.instance:

…如果您确定Elvis尚未创建,而King已经创建。

但它鼓励用户普遍使用the方法:

1
Elvis.the().leave(Building.the())

要完成此操作,还可以覆盖__delattr__(),以便在尝试删除instance时引发异常,并覆盖__del__(),以便引发异常(除非我们知道程序正在结束……)

进一步改进

我要感谢那些帮助我进行评论和编辑的人,我们欢迎更多的评论和编辑。虽然我使用Jython,但这应该更通用,并且是线程安全的。

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
try:
    # This is jython-specific
    from synchronize import make_synchronized
except ImportError:
    # This should work across different python implementations
    def make_synchronized(func):
        import threading
        func.__lock__ = threading.Lock()

        def synced_func(*args, **kws):
            with func.__lock__:
                return func(*args, **kws)

        return synced_func

class Elvis(object): # NB must be subclass of object to use __new__
    instance = None

    @classmethod
    @make_synchronized
    def __new__(cls, *args, **kwargs):
        if cls.instance is not None:
            raise Exception()
        cls.instance = object.__new__(cls, *args, **kwargs)
        return cls.instance

    def __init__(self):
        pass
        # initialisation code...

    @classmethod
    @make_synchronized
    def the(cls):
        if cls.instance is not None:
            return cls.instance
        return cls()

注意点:

如果在python2中没有从object子类化。您将得到一个老式的类,它不使用__new__在装饰__new__时,必须使用@classmethod进行装饰,否则__new__将是一个未绑定的实例方法这可以通过使用元类来改进,因为这将允许您创建the类级属性,并可能将其重命名为instance


我要把我的扔进斗牛场。它是一个简单的装饰器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from abc import ABC

def singleton(real_cls):

    class SingletonFactory(ABC):

        instance = None

        def __new__(cls, *args, **kwargs):
            if not cls.instance:
                cls.instance = real_cls(*args, **kwargs)
            return cls.instance

    SingletonFactory.register(real_cls)
    return SingletonFactory

# Usage
@singleton
class YourClass:
    ...  # Your normal implementation, no special requirements.

我认为它的好处超过了其他一些解决方案:

答案为c。它的动作是完全封装的。您不需要对YourClass的实现做任何更改。这包括不需要为您的类使用元类(注意上面的元类在工厂中,而不是"真正的"类)。它不依赖于猴子修补任何东西。它对来电者是透明的:调用者仍然只是简单地导入YourClass,它看起来像一个类(因为它是),并且它们通常使用它。不需要使调用者适应工厂功能。YourClass()实例化的仍然是您实现的YourClass的一个真实实例,而不是任何类型的代理,因此不会产生副作用。isinstance(instance, YourClass)和类似的操作仍然像预期的那样工作(尽管这个位需要abc,所以排除了Python <2.6)。

我确实遇到了一个缺点:真实类的类方法和静态方法不能通过隐藏它的工厂类透明地调用。我很少使用这种方法,所以我从来没有遇到过这种需要,但是通过在实现__getattr__()的工厂上使用自定义元类将所有ish属性访问委托给真正的类,可以很容易地纠正这种情况。

实际上,我发现一个更有用的相关模式(并不是说这类东西经常是必需的)是"惟一的"模式,使用相同的参数实例化类会得到相同的实例。即"每个参数一个单例"。以上内容很好地适应了这一点,并且变得更加简洁:

1
2
3
4
5
6
7
8
9
10
def unique(real_cls):

    class UniqueFactory(ABC):

        @functools.lru_cache(None)  # Handy for 3.2+, but use any memoization decorator you like
        def __new__(cls, *args, **kwargs):
            return real_cls(*args, **kwargs)

    UniqueFactory.register(real_cls)
    return UniqueFactory

综上所述,我同意一个普遍的建议,如果你认为你需要这些东西,你真的应该停下来问问自己,如果你真的需要。99%的时间,YAGNI。


一句话(我并不自豪,但它确实管用):

1
2
3
4
class Myclass:
  def __init__(self):
      # do your stuff
      globals()[type(self).__name__] = lambda: self # singletonify


如果你不需要单例实例的延迟初始化,那么下面的操作应该是简单和线程安全的:

1
2
3
4
class A:
    instance = None
    # Methods and variables of the class/object A follow
A.instance = A()

通过这种方式A是在模块导入时初始化的单例对象。


我不记得在哪里找到的这个解决方案,但我发现它是最"优雅"的从我的非python专家的观点:

1
2
3
4
5
6
7
8
9
10
11
12
class SomeSingleton(dict):
    __instance__ = None
    def __new__(cls, *args,**kwargs):
        if SomeSingleton.__instance__ is None:
            SomeSingleton.__instance__ = dict.__new__(cls)
        return SomeSingleton.__instance__

    def __init__(self):
        pass

    def some_func(self,arg):
        pass

我为什么喜欢这个?没有装饰器,没有元类,没有多重继承……如果您决定不再让它成为单例对象,只需删除__new__方法。由于我刚接触Python(以及OOP),我希望有人能告诉我为什么这是一种糟糕的方法?


这个答案可能不是你想要的。我想要一个单例,在某种意义上,只有那个对象有它的标识,作为比较。在我的例子中,它被用作一个标记值。答案很简单,让任何对象mything = object()根据python的本质,只有那个对象才有它的标识。

1
2
3
4
5
6
#!python
MyNone = object()  # The singleton

for item in my_list:
    if item is MyNone:  # An Example identity comparison
        raise StopIteration


这个解决方案在模块级造成了一些命名空间污染(三个定义而不是一个),但是我发现它很容易遵循。

我希望能够编写类似这样的东西(延迟初始化),但不幸的是,类在它们自己的定义体中不可用。

1
2
3
4
5
6
7
8
9
# wouldn't it be nice if we could do this?
class Foo(object):
    instance = None

    def __new__(cls):
        if cls.instance is None:
            cls.instance = object()
            cls.instance.__class__ = Foo
        return cls.instance

因为这是不可能的,所以我们可以将初始化和静态实例分离出来

急切的初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import random


class FooMaker(object):
    def __init__(self, *args):
        self._count = random.random()
        self._args = args


class Foo(object):
    def __new__(self):
        return foo_instance


foo_instance = FooMaker()
foo_instance.__class__ = Foo

延迟初始化:

急切的初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import random


class FooMaker(object):
    def __init__(self, *args):
        self._count = random.random()
        self._args = args


class Foo(object):
    def __new__(self):
        global foo_instance
        if foo_instance is None:
            foo_instance = FooMaker()
        return foo_instance


foo_instance = None


这是我实现单例的首选方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Test(object):
    obj = None

    def __init__(self):
        if Test.obj is not None:
            raise Exception('A Test Singleton instance already exists')
        # Initialization code here

    @classmethod
    def get_instance(cls):
        if cls.obj is None:
            cls.obj = Test()
        return cls.obj

    @classmethod
    def custom_method(cls):
        obj = cls.get_instance()
        # Custom Code here