关于python的单列模式

  • Post author:
  • Post category:python


单例模式

一种常用的软件设计模式。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

动机:对于一些类来说,只有一个实例是很重要的。比如一个班级只能有一个班主任、一个数字滤波器只能有一个A/D转换器。那么,我们怎样才能保证一个类只有一个实例并且这个实例易于被访问?一个全局变量使得一个对象可以被访问,但是它不能防止你实例化多个对象。这样就有了一个更好的办法,让类自身负责保护它的唯一实例,这个类可以保证没有其他实例被创建,并且可以提供一个访问该实例的方法,这就是单例模式

哪些情况可以使用单例模式?

  • 当类只能有一个实例而且客户可以从一个人们都知道的访问点访问它时。
  • 当这个唯一实例应该是可以通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

单例模式有什么优点

  • 避免对资源的多重占用,比如文件系统。
  • 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。

python实现单例模式的几种方式

  • 使用模块。其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:
class Singleton(object):
    def foo(self):
        pass
singleton = Singleton()

将上面的代码单独放在一个文件中,用的时候,在其他文件中导入这个对象,这个对象就是单例模式的对象。

  • 使用装饰器
def Singleton(cls):
    instance = {}

    def singleton(*args, **kargs):
        if cls not in instance:
            instance[cls] = cls(*args, **kargs)
        return instance[cls]

    return singleton
    
@Singleton
class A(object):
    a = 1
    def __init__(self, x=0):
        self.x = x
        
a1 = A(2)
a2 = A(3)
  • 基于@classmethod,未加锁部分并发执行,加锁部分串行执行,速度降低,但是保证了数据安全
import time
import threading
class Singleton(object):
    instance_lock = threading.Lock()

    def __init__(self):
        pass

    @classmethod
    def instance(cls, *args, **kwargs):
        with Singleton.instance_lock:
            if not hasattr(Singleton, "_instance"):
                Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance
  • 基于__new__方法实现
class Singleton:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,'_instance'):#如果不存在这个属性,那么给它造一个
            _instance=super().__new__(cls,*args,**kwargs)
            cls._instance=_instance
        return cls._instance
class Myclass(Singleton):
    pass
c1=Myclass()
c2=Myclass()
#验证一下是不是单例
assert c1 is c2

采用这种方式的单例模式,以后实例化对象时,和平时实例化对象的方法一样 obj = Singleton()

参考https://www.cnblogs.com/huchong/p/8244279.html



版权声明:本文为qq_42199781原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。