一、什么是单例模式?
"""
单例模式:
单例模式是一个软件的设计模式,为了保证一个类,无论调用多少次产生的实例对象,
都是指向同一个内存地址,仅仅只有一个实例(对象)!
五种单例:
- 模块
- 装饰器
- 元类
- __new__
- 类方法: classmethod
"""
二、单例模式的实现
1.通过类方法实现单例模式
'''
方式一: @classmethod ---> 通过类方法来实现单例
'''
class Foo(object):
# 定义了一个类的数据属性,
# 用于接收对象的实例,判断对象的实例是否只有一个
_instance = None # obj1
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def singleton(cls, *args, **kwargs):
# 判断类属性_instance是否有值,有代表已经有实例对象
# 没有则代表没有实例对象,则调用object的__init__获取实例对象
if not cls._instance:
# object.__new__(cls): 创造对象
# 没有参数情况下
# cls._instance = object.__new__(cls, *args, **kwargs)
# 有参数的情况下
cls._instance = cls(*args, **kwargs) # 相当于Foo()
# 将已经产生的实例对象 直接返回
return cls._instance
obj1 = Foo.singleton('yessir', '123')
obj2 = Foo.singleton('yessir', '123')
# print(obj1 is obj2)
2.通过元类实现单例模式
'''
方式二: 元类
'''
class MyMeta(type):
# 1、先触发元类里面的__init__
def __init__(self, name, base, attrs): # self --> Goo
# *** 造空的对象, 然后赋值给了Goo类中的_instance类属性
self._instance = object.__new__(self)
# 将类名、基类、类的名称空间,传给type里面的__init__
super().__init__(name, base, attrs)
# type.__init__(self, name, base, attrs)
# 2、当调用Goo类时,等同于调用了由元类实例化的到的对象
def __call__(self, *args, **kwargs):
# 判断调用Goo时是否传参
if args or kwargs:
init_args = args
init_kwargs = kwargs
# 1)通过判断限制了用于传入的参数必须一致,然后返回同一个对象实例
if init_args == args and init_kwargs == kwargs:
return self._instance
# 2) 若不是同一个实例,则新建一个对象,产生新的内存地址
obj = object.__new__(self)
self.__init__(obj, *args, **kwargs)
return obj
return self._instance
class Goo(metaclass=MyMeta): # Goo = MyMeta(Goo)
# _instance = obj
def __init__(self, x):
self.x = x
g1 = Goo('1')
g2 = Goo('1')
# print(g1 is g2) # True
3.通过__new__方法实现单例模式
'''
方式三: __new__实现 ---> 通过调用类方法实例化对象时,自动触发的__new__来实现单例
'''
class Aoo(object):
_instance = None
def __new__(cls, *args, **kwargs):
# if not hasattr(cls,'_instance'):
if not cls._instance: # 这里本质跟上面那句一样,上面用反射
cls._instance = object.__new__(cls)
return cls._instance
a1 = Aoo()
a2 = Aoo()
# print(a1 is a2) # True
4.通过装饰器实现单例模式
'''
方式四: 装饰器实现 ---> 通过调用类方法实例化对象时,自动触发的__new__来实现单例
定义一个装饰器,将类传入,内部通过逻辑判断是否有创建过对象,如果没有,创建一个新对象,如果有,直接用之前的对象。
'''
def singleton_wrapper(cls):
_instance = {} # 定义一个空字典,构造出{'Foo':Foo,'Aoo':Aoo,'Boo':Boo}这样的字典
def inner(*args,**kwargs):
if cls not in _instance:
_instance[cls] = cls(*args,**kwargs)
return _instance[cls] # _instance['Foo']=Foo,此时的_instance={'Foo':Foo}
return inner # inner=Foo,此时的_instance={'Foo':Foo}
@singleton_wrapper # Foo = singoleton_wrapper(Foo) ==> Foo = inner
class Foo():
pass
s1 = Foo() # Foo()就是inner()
s2 = Foo()
print("s1",id(s1))
print("s2",id(s2))
print(s1 is s2)
print(s1 == s2)
5.通过模块导入实现单例
'''
方式五: 模块导入实现
模块导入是天然的单例,也是最简单容易实现的一种方式
'''
import cls_singleton
s1 = cls_singleton.instance
s2 = cls_singleton.instance
print(s1 is s2) # True