Python之单例模式
一、介绍
单例模式是一种常用的软件设计模式,属于创建型模式。单例模式的核心结构就是系统中一个类只有一个实例,保证了在程序的不同位置都可以且仅可以取到同一个对象实例。
应用场景:
1.单例模式广泛应用于各种开发场景:
游戏中需要有“场景管理器”这样一种东西,用来管理游戏场景的切换、资源载入、网络连接等等任务。这个管理器需要有多种方法和属性,在代码中很多地方会被调用,且被调用的必须是同一个管理器,否则既容易产生冲突,也会浪费资源
2.一些资源管理器常常设计成单例模式:
在计算机系统中,需要管理的资源包括软件外部资源,譬如每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印机作业同时输出到打印机中。每台计算机可以有若干传真机卡,但是只应该有一个软件负责管理传真卡,以避免一个通信端口同时被两个请求同时调用。
需要管理的资源包括软件内部资源,譬如,大多数的软件都有一个(甚至多个)属性(properties)文件存放系统配置。这样的系统应当由一个对象来管理一个属性文件。
二、单例模式
1、常用的单例模式
class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls) return cls._instance s1 = Singleton() s2 = Singleton() print(s1 is s2) # True
属性共用的单例
""" 上面的第一种写法,虽然创建的是同一个实例, 但是属性是不共用的,因为每次__init__都会重新设置 """ class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls) return cls._instance def __init__(self, name, age): self.name = name self.age = age s1 = Singleton(name="小明", age=18) print(s1.name, s1.age) # 小明 18 s2 = Singleton(name="小红", age=17) # 这里相当于是重新赋值了name和age,之后的name age都是这个值 print(s2.name, s2.age) # 小红 17 print(s1 is s2) # True """ 因此想要属性也共用,__init__也需要处理 """ class Singleton(object): _instance = None _initialized = False def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls) return cls._instance def __init__(self, name, age): if not Singleton._initialized: self.name = name self.age = age Singleton._initialized = True s1 = Singleton(name="小明", age=18) print(s1.name, s1.age) # 小明 18 s2 = Singleton(name="小红", age=17) print(s2.name, s2.age) # 小明 18 print(s1 is s2) # True
加锁的单例
import time import threading class Singleton(object): lock = threading.RLock() # 定义一把锁 _instance = None def __new__(cls, *args, **kwargs): if cls._instance: return cls._instance # 如果之前实例化过,没必要再次实例化,因为都是同一个实例 with cls.lock: # 避免当线程没有返回实例前,另一个线程也进来了,导致出现不止一个实例 if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls) return cls._instance def task(arg): obj = Singleton() print(obj) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() time.sleep(10) obj = Singleton()
2、函数单例装饰器
def singleton(cls): _instance = {} def _singleton(*args, **kwargs): if cls not in _instance: _instance[cls] = cls(*args, **kwargs) return _instance[cls] return _singleton @singleton class A(): def __init__(self, name): self.name = name a1 = A("ming") print(a1.name) # ming a2 = A("dong") print(a2.name) # ming
3、类单例装饰器
class Singleton(object): def __init__(self, cls): self._cls = cls self._instance = {} def __call__(self, *args, **kwargs): if self._cls not in self._instance: self._instance[self._cls] = self._cls(*args, **kwargs) return self._instance[self._cls] @Singleton class A(): def __init__(self, name): self.name = name a1 = A("ming") print(a1.name) # ming a2 = A("dong") print(a2.name) # ming
4、使用 metaclass 实现单例模式
class Singleton(type): _instance = {} def __call__(cls, *args, **kwargs): if cls not in cls._instance: cls._instance[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instance[cls] class A(metaclass=Singleton): def __init__(self, name): self.name = name a1 = A("ming") print(a1.name) # ming a2 = A("dong") print(a2.name) # ming