python实现单例模式的5种方法

时间:2022-07-22
本文章向大家介绍python实现单例模式的5种方法,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

单例模式

相信大家都知道单例模式

单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”

单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

那么,为什么不直接使用全局变量,而要搞一个单例出来?单例到底比全局变量好在哪儿?

  首先,全局变量不能保证全局只有一个类的实例,你完全可以声明同一个类的多个实例。当然,如果你注意一点,那么用全局方法保证全局只有一个该类的实例还是可以做到的,但你得很注意,让自己不要在其他地方声明多一个实例。而单例却可以轻松的做到这一点,并能保证全局只有一个该类的实例可被访问。

  其次,相对来说,使用单例时,代码会显得优雅一些。

什么时候用单例

  单例的使用主要是在需要保证全局只有一个实例可以被访问的情况,比如系统日志的输出、操作系统的任务管理器等。

一、使用new方法

class Singleton(object):
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance
 
class MyClass(Singleton):
    a = 1

二、共享属性

class Borg(object):
    _state = {}
    def __new__(cls, *args, **kw):
        ob = super(Borg, cls).__new__(cls, *args, **kw)
         ob.__dict__ = cls._state
    return ob
 
class MyClass2(Borg):
    a = 1

创建实例时把所有实例的dict指向同一个字典,这样它们具有相同的属性和方法.

三、装饰器版本

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

四、import方法

作为python的模块是天然的单例模式

# mysingleton.py
class My_Singleton(object):
    def foo(self):
        pass
 
my_singleton = My_Singleton()
 
# to use
from mysingleton import my_singleton
 
my_singleton.foo()

五、使用元类方法

class Singleton2(type):
    def __init__(self, *args, **kwargs):
        self.__instance = None
        super(Singleton2,self).__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(Singleton2,self).__call__(*args, **kwargs)
        return self.__instance


class Foo(object):
    __metaclass__ = Singleton2 #在代码执行到这里的时候,元类中的__new__方法和__init__方法其实已经被执行了,而不是在Foo实例化的时候执行。且仅会执行一次。


foo1 = Foo()
foo2 = Foo()
print (Foo.__dict__)  #_Singleton__instance': <__main__.Foo object at 0x100c52f10> 存在一个私有属性来保存属性,而不会污染Foo类(其实还是会污染,只是无法直接通过__instance属性访问)

print (foo1 is foo2)  # True