单例模式
-
学习单例模式就是为了,防止内存地址混乱
-
实例化得到一个对象,内存地址相同
【一】什么是单例模式
-
单例设计模式(Singleton Design Pattern):一个类只允许创建一个对象(或者实例),那么这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。
-
当一个类的功能比较单一,只需要一个实例对象就可以完成需求时,就可以使用单例模式来节省内存资源。
【通常】单例模式创建的对象是进程唯一的, 单例类中对象的唯一性的作用范围是进程内的,在进程间是不唯一的。
【二】实现单例模式的方法
-
使用模块
-
使用装饰器
-
使用类(方法)
-
基于
__new__
方法实现 -
基于元类metaclass实现
【三】类属性
(1)类产生对象
-
创建一个普通的类
class MysqlControl(object):
...
#类只要加 () 实例化就会产生一个全新的对象
one = MysqlControl()
two = MysqlControl()
#查看对象 --- 发现虽然是同一个类实例化得到的对象,但是对象的地址不一样
print(one)#<__main__.MysqlControl object at 0x0000025C0F2FFFD0>
print(two)#<__main__.MysqlControl object at 0x0000025C0F2FECB0>
print(one is two)#False
-
虽然是同一个类实例化得到的对象,但是对象的地址不一样
(2)类属性包装成方法
class Singleton(object):
_instance = None
def __init__(self, ip, port):
self.ip = ip
self.port = port
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = Singleton('127.0.0.1', 3306)
return cls._instance
obj_one = Singleton.get_instance()
obj_two = Singleton.get_instance()
print(obj_one)
#<__main__.Singleton object at 0x00000226E33B7E80>
print(obj_two)
# <__main__.Singleton object at 0x00000226E33B7E80>
print(obj_one is obj_two)
# True
# 输出 True,表示是同一个实例
-
使用类属性保存属性,通过类方法获取实例
-
在第一次调用
get_instance
方法时创建实例,并在后续调用中直接返回该实例。
(3)装饰器
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
print(cls)#<class '__main__.Singleton'>
#得到一个字典,{类:对象}
print(instances)#{<class '__main__.Singleton'>: <__main__.Singleton object at 0x000002D50E217E20>}
#字典的特性,键取值
print(instances[cls])#得到对象#<__main__.Singleton object at 0x000002D50E217E20>
#存在直接返回对象
return instances[cls]
return wrapper
@singleton
class Singleton:
pass
singleton_one = Singleton()
singleton_two = Singleton()
print(singleton_one)
# <__main__.Singleton object at 0x000001C0B531A770>
print(singleton_two)
# <__main__.Singleton object at 0x000001C0B531A770>
print(singleton_one is singleton_two)
# True
# 输出 True,表示是同一个实例
# # 使用 __call__ 方法获取单例
singleton_three = Singleton()
print(singleton_one is singleton_three)
# True
-
使用装饰器将原来的类包装成一个新的类,通过闭包和字典保存实例。
-
在每次实例化时,先检查字典中是否已经存在该类的实例,如果不存在才创建实例并返回。
(4)元类(metaclass)
class Singleton(object):
def __new__(cls, *args, **kwargs):
#instance相当于一个标志位
#cls里面有没有这个instance属性,或者实例
if not hasattr(cls, 'instance'):
#得到一个对象
cls.instance = super().__new__(cls)
#就是为了生成一个对象
print(super().__new__(cls))##<__main__.Singleton object at 0x000001C03DA97E50>
print(cls)#<class '__main__.Singleton'>
print(cls.instance)#<__main__.Singleton object at 0x000001C03DA97E50>
print(hasattr(cls, 'instance'))#True
print(cls.instance)#<__main__.Singleton object at 0x00000284256C7E50>
return cls.instance
singleton_one = Singleton()
singleton_two = Singleton()
print(singleton_one)
#<__main__.Singleton object at 0x000002232A817E80>
print(singleton_two)
# <__main__.Singleton object at 0x000002232A817E80>
print(singleton_one is singleton_two)
# True
# 输出 True,表示是同一个实例
# 使用 __call__ 方法获取单例
singleton_three = Singleton()
print(singleton_one is singleton_three)
# True
-
定义一个元类,在元类的
__call__
方法中判断实例是否已存在,如果不存在则调用父类的__call__
方法来创建并返回实例。
(5)基于__new__
方法
(1)思路
-
在Python中,对象的实例化过程通常遵循以下步骤:
-
首先,执行类的
__new__
方法,如果未定义此方法,将默认调用父类的__new__
方法来创建一个实例化对象。 -
接着,再执行
__init__
方法来对这个新创建的对象进行初始化。
-
-
我们可以充分利用这个实例化过程来实现单例模式。
-
具体做法是在类的
__new__
方法中判断是否已经存在实例,如果存在,则直接返回现有的实例,否则创建一个新的实例。 -
这样就能够确保只有一个实例存在,从而实现了单例模式的效果。
-
class Singleton(object):
def __new__(cls, *args, **kwargs):
#instance相当于一个标志位
#cls里面有没有这个instance属性,或者实例
if not hasattr(cls, 'instance'):
#得到一个对象
cls.instance = super().__new__(cls)
#就是为了生成一个对象
print(super().__new__(cls))##<__main__.Singleton object at 0x000001C03DA97E50>
print(cls)#<class '__main__.Singleton'>
print(cls.instance)#<__main__.Singleton object at 0x000001C03DA97E50>
print(hasattr(cls, 'instance'))#True
print(cls.instance)#<__main__.Singleton object at 0x00000284256C7E50>
return cls.instance
singleton_one = Singleton()
singleton_two = Singleton()
print(singleton_one)
#<__main__.Singleton object at 0x000002232A817E80>
print(singleton_two)
# <__main__.Singleton object at 0x000002232A817E80>
print(singleton_one is singleton_two)
# True
# 输出 True,表示是同一个实例
# 使用 __call__ 方法获取单例
singleton_three = Singleton()
print(singleton_one is singleton_three)
# True
-
重写
__new__
方法,在实例化对象时判断类中是否已有实例,如果没有则调用父类的__new__
方法来创建并返回。
【6】基于模块
# singleton.py
class Singleton:
pass
singleton_instance = Singleton()
-
将实例化操作放在模块级别,通过导入该模块来获取实例。
-
由于Python模块在运行时只会被导入一次,因此保证了实例的单一性。