Python 设计模式 - 单例模式
单例模式是一种比较常见的设计模式,所以顺理成章的成为我们第一个介绍的设计模式。 应用场景:
- 资源共享。例如,数据库连接,配置管理,日志管理。
实现方法有多种:
- 使用**_new_**
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls) #这里需要注意不能使用cls(), 否则会导致无限递归
return cls._instance
ins1 = Singleton()
ins2 = Singleton()
id(ins1) == id(ins2) # True
- 使用闭包/函数装饰器
闭包使得自由变量instance在**_singleton**调用完成后没有被释放,跟上诉方法中的类变量作用一样。
from functools import wraps
def _singleton(cls):
instance = {}
@wraps(cls)
def func(*args,**kwargs):
if cls not in instance:
instance[cls] = cls(*args,**kwargs)
return instance[cls]
return func
@_singleton
class Singleton:
pass
ins1 = Singleton()
ins2 = Singleton()
id(ins1) == id(ins2) # True
- 使用类装饰器 是的装饰器除了函数也可以说是类,在类作为装饰器时,会调用类的**__call__**方法
class GenSingleton:
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]
@GenSingleton
class Singleton:
pass
s1 = Singleton()
s2 = Singleton()
print(id(s1) == id(s2)) # True
- 使用metaclass
class SingletonType(type):
def __init__(cls, *args, **kwargs):
"""
在编译时调用该方法
"""
cls._instance = None
def __call__(cls, *args, **kwargs):
"""
在实例化类时调用该方法
"""
if cls._instance is None:
cls._instance = super().__call__(*args, **kwargs)
return cls._instance
class Singleton(metaclass=SingletonType):
pass
s1 = Singleton()
s2 = Singleton()
print(id(s1) == id(s2)) # True
对于Python引入机制熟悉的同学应该知道Python中的模块只会import一次,所以算是天然的单例模式。当然究其原因是在第一次import时会生成pyc文件,以后import时会直接读取pyc内容。
- 使用模块
singleton.py
class Singleton:
pass
s = Singleton()
usage.py
from singleton import s as s1
from singleton import s as s2
print(id(s1) == id(s2)) # True
当然实现方式还有不少,但实质上差别不大,我们平时使用的时候掌握其中之一即可。