单例模式-Python 实现

什么是单例模式 ?

单例模式(Singleton Pattern)是软件设计中的一种常用设计模式,其目的是在一个进程中,确保某一个类(class)只有一个实例(instance)存在。
例如,当我们在操作数据库时,多个服务都要调用数据库的 connection ,其配置信息都是相同的,这种情况就可以使用单例模式。在该系统中,只使用一个用于连接数据库的 connection 实例

单例模式的实现方式

1. 模块构建

Python 的模块就是天然的单例模式,模块在第一次导入的时候,会生成 .pyc 文件,就会直接加载.pyc文件,而不会再次执行模块
因此,我们只需要把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

Singleton.py

1
2
3
4
5
6
class Singleton(object):
def __int__(self):
pass


singleton = Singleton()

当我们需要使用这个 instance 的时候,直接使用即可:

1
from Singleton import singleton

装饰器

使用 dict 类型,以 key-value 方式存储类的实例和运行的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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(object):
def __init__(self, x):
self.x = x

a1 = A(1)
a2 = A(2)

print(a1 is a2)

类方法实现

使用方法 hasattr 方法判断类中是否已实现了对应的实例方法,实现了就直接返回,未返回就添加单例属性

1
2
3
4
5
6
7
8
9
10
11
12
class Singleton(object):
def __init__(self):
pass

@staticmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance

obj = Singleton.instance()

多线程场景

但是在多线程的使用中,由于每个线程有自己的数据资源,所以会存在问题

1
2
3
4
5
6
7
8
def task(arg):
obj = Singleton.instance()
print(obj) # 显示 instance 的详情信息

for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()

以上的实例显示出的详情可以看到 obj 的 id 并不一致,解决办法就是加 (mutex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import time
import threading

class Singleton(object):
lock = threading.Lock()
def __init__(self):
time.sleep(1)

@staticmethod
def instance(cls, *args, **kwargs):
with Singleton.lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance

以上实现方式对整个实例的创建过程都进行了加锁,可以进行优化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import time
import threading

class Singleton(object):
lock = threading.Lock()
def __init__(self):
time.sleep(1)

@staticmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton.lock:
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance

但是这样的实现方式,需要借助 instance 方法

__new__ 方法实现

一个类在被实例化的过程中,先是执行默认的__new__ 方法,然后再执行__init__方法初始化对象

1
2
3
4
5
6
7
8
9
10
11
12
import threading

class Singleton(object):
_instance_lock = threading.Lock()
def __int__(self):
pass

def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with cls._instance_lock:
cls._instance = super.__new__(cls)
return cls._instance

metaclass 方式实现

  1. 类由 type创建,创建类时,type 的 __init__ 方法自动执行,类() 的方式执行type__call__方法(类的 new__、__init 方法)
  2. 对象由类创建,创建对象时,类的 __init__ 方法自动执行,对象()执行类的__call__ 方法

其实,我们就是要保证在创建类的时候,保证这个类只有一个实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import threading

class SingletonType(type):
_instance_lock = threading.Lock

def __call__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with SingletonType._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = super.__call__(*args, **kwargs)
return cls._instance

class Foo(metaclass=SingletonType):
def __int__(self, name):
self.name = name

-------------THANKS FOR READING-------------