-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSingleton
More file actions
138 lines (110 loc) · 4.3 KB
/
Singleton
File metadata and controls
138 lines (110 loc) · 4.3 KB
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# 定义轿车类,没有三个属性不行
class CarMeta(type):
def __init__(self,class_name,class_bases,class_dic):
# 从类的名称空间找要求的属性
if not class_dic.get('production_date') and not class_dic.get('engine_number') and not class_dic.get('capacity'):
raise TypeError('类缺少必要属性')
# 我们重写了init方法,但是不能全部重写,所以还要重用父类的功能
super(CarMeta,self).__init__(class_name,class_bases,class_dic)
def __call__(self, *args, **kwargs):
# 创建类的一个空对象
obj = object.__new__(self)
# 把obj对象和类括号的数据传给类的初始化函数__init__
self.__init__(obj,*args,**kwargs)
# 返回实例化之后的对象
return obj
class Car(object,metaclass=CarMeta):
# production_date = '0.0.0'
# engine_number = 0
# capacity = 0
pass
'''
Singleton
意图:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
适用性:
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
'''
# 1.修改类的__new__方法
class Singleton():
def __init__(self,x):
print('__init__ is run')
self.x = x
def __new__(self,*args,**kwargs):
print('__new__ is run')
if not hasattr(self,'instance'): # 如果对象中还没有实例的属性,说明还没有创建实例,
self.instance = object.__new__(self) # 创建空实例,实例化德过程是先创建空对象再初始化,也就是先new再init
return self.instance # 返回实例,在第二次调用时候会返回第一次生成的实例,但是还是空实例,相当于空壳没变
obj = Singleton(1)
obj2 = Singleton(2)
print(obj is obj2)
print(obj.x)
# 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 Foo():
pass
f =Foo()
f1 = Foo()
print(f,f is f1)
# 3.类方法来实现
class Singleton:
@classmethod
def instance(self,*args,**kwargs):
if not hasattr(Singleton,'_instance'):
Singleton._instance = Singleton(*args,**kwargs)
return Singleton._instance
foo1 = Singleton.instance()
foo2 = Singleton.instance()
print(foo1 is foo2)
print(foo1)
# 4.元类实现
class Singleton(type):
def __init__(cls, *args, **kwargs):
cls.__instance = None
super().__init__(*args, **kwargs)
# __call__ 是对于类实例有效,比如说Spam类,是type类的实例
def __call__(cls, *args, **kwargs):
print('Singleton __call__ running')
if cls.__instance is None:
'''
元类定义__call__方法,可以抢在类运行 __new__ 和 __init__ 之前执行,
也就是创建单例模式的前提,在类实例化前拦截掉。
type的__call__实际上是调用了type的__new__和__init__,返回了一个spam类的对象
'''
cls.__instance = super().__call__(*args, **kwargs)
print(cls.__instance)
return cls.__instance
else:
return cls.__instance
class Spam(metaclass=Singleton):
def __new__(cls):
print('Spam __new__ running')
return super().__new__(cls)
def __init__(self):
print('Spam __init__ running')
if __name__ == '__main__':
a = Spam()
b = Spam()
print(a is b)
c = Spam()
print(a is c)
# 5.使用模块的方法
"""
其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,
当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,
就可以获得一个单例对象了。
"""
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
# 将上面的代码保存在文件 py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象
from a import singleton