单例模式是一种比较常见的设计模式,所以顺理成章的成为我们第一个介绍的设计模式。
应用场景:
实现方法有多种:
1 2 3 4 5 6 7 8 9 10 11 12
| class Singleton: _instance = None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance ins1 = Singleton() ins2 = Singleton() id(ins1) == id(ins2)
|
闭包使得自由变量instance在_singleton调用完成后没有被释放,跟上诉方法中的类变量作用一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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)
|
- 使用类装饰器
是的装饰器除了函数也可以说是类,在类作为装饰器时,会调用类的__call__方法
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
| 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))
|
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
| 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))
|
对于Python引入机制熟悉的同学应该知道Python中的模块只会import一次,所以算是天然的单例模式。当然究其原因是在第一次import时会生成pyc文件,以后import时会直接读取pyc内容。
singleton.py
1 2 3 4
| class Singleton: pass s = Singleton()
|
usage.py
1 2 3 4
| from singleton import s as s1 from singleton import s as s2
print(id(s1) == id(s2))
|
当然实现方式还有不少,但实质上差别不大,我们平时使用的时候掌握其中之一即可。