Skip to content

Commit fee088d

Browse files
committed
add singleton
1 parent 3ca55e7 commit fee088d

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

Class/singleton.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# 单例模式
2+
3+
**单例模式(Singleton Pattern)**是一种常用的软件设计模式,该模式的主要目的是确保**某一个类只有一个实例存在**。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
4+
5+
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
6+
7+
在 Python 中,我们可以用多种方法来实现单例模式:
8+
9+
- 使用模块
10+
- 使用 `__new__`
11+
- 使用装饰器(decorator)
12+
- 使用元类(metaclass)
13+
14+
# 使用模块
15+
16+
其实,**Python 的模块就是天然的单例模式**,因为模块在第一次导入时,会生成 `.pyc` 文件,当第二次导入时,就会直接加载 `.pyc` 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:
17+
18+
```python
19+
# mysingleton.py
20+
class My_Singleton(object):
21+
def foo(self):
22+
pass
23+
24+
my_singleton = My_Singleton()
25+
```
26+
27+
将上面的代码保存在文件 `mysingleton.py` 中,然后这样使用:
28+
29+
```
30+
from mysingleton import my_singleton
31+
32+
my_singleton.foo()
33+
```
34+
35+
# 使用 `__new__`
36+
37+
为了使类只能出现一个实例,我们可以使用 `__new__` 来控制实例的创建过程,代码如下:
38+
39+
```python
40+
class Singleton(object):
41+
_instance = None
42+
def __new__(cls, *args, **kw):
43+
if not cls._instance:
44+
cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
45+
return cls._instance
46+
47+
class MyClass(Singleton):
48+
a = 1
49+
```
50+
51+
在上面的代码中,我们将类的实例和一个类变量 `_instance` 关联起来,如果 `cls._instance` 为 None 则创建实例,否则直接返回 `cls._instance`
52+
53+
执行情况如下:
54+
55+
```
56+
>>> one = MyClass()
57+
>>> two = MyClass()
58+
>>> one == two
59+
True
60+
>>> one is two
61+
True
62+
>>> id(one), id(two)
63+
(4303862608, 4303862608)
64+
```
65+
66+
# 使用装饰器
67+
68+
我们知道,装饰器(decorator)可以动态地修改一个类或函数的功能。这里,我们也可以使用装饰器来装饰某个类,使其只能生成一个实例,代码如下:
69+
70+
```
71+
from functools import wraps
72+
73+
def singleton(cls):
74+
instances = {}
75+
@wraps(cls)
76+
def getinstance(*args, **kw):
77+
if cls not in instances:
78+
instances[cls] = cls(*args, **kw)
79+
return instances[cls]
80+
return getinstance
81+
82+
@singleton
83+
class MyClass(object):
84+
a = 1
85+
```
86+
87+
在上面,我们定义了一个装饰器 `singleton`,它返回了一个内部函数 `getinstance`,该函数会判断某个类是否在字典 `instances` 中,如果不存在,则会将 `cls` 作为 key,`cls(*args, **kw)` 作为 value 存到 `instances` 中,否则,直接返回 `instances[cls]`
88+
89+
# 使用 metaclass
90+
91+
元类(metaclass)可以控制类的创建过程,它主要做三件事:
92+
93+
- 拦截类的创建
94+
- 修改类的定义
95+
- 返回修改后的类
96+
97+
使用元类实现单例模式的代码如下:
98+
99+
```python
100+
class Singleton(type):
101+
_instances = {}
102+
def __call__(cls, *args, **kwargs):
103+
if cls not in cls._instances:
104+
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
105+
return cls._instances[cls]
106+
107+
# Python2
108+
class MyClass(object):
109+
__metaclass__ = Singleton
110+
111+
# Python3
112+
# class MyClass(metaclass=Singleton):
113+
# pass
114+
```
115+
116+
# 小结
117+
118+
- Python 的模块是天然的单例模式,这在大部分情况下应该是够用的,当然,我们也可以使用装饰器、元类等方法
119+
120+
# 参考资料
121+
122+
- [Creating a singleton in Python - Stack Overflow](http://stackoverflow.com/questions/6760685/creating-a-singleton-in-python)
123+
- [深入浅出单实例Singleton设计模式 | 酷 壳](http://coolshell.cn/articles/265.html)
124+
- [design patterns - Python's use of __new__ and __init__? - Stack Overflow](http://stackoverflow.com/questions/674304/pythons-use-of-new-and-init)
125+
126+

0 commit comments

Comments
 (0)