← 回到学习笔记
Python基础学习笔记之单例模式
保留单例模式的核心实现与使用边界。
学习目标
保留单例模式的核心实现与使用边界。
一、单例设计模式【重点掌握】
1.概念
什么是设计模式?
设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案
设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言
23种设计模式,其中比较常用的是单例设计模式,工厂设计模式,代理模式,装饰者模式等等
什么是单例设计模式?
单例:单个实例/单个对象,一个类只能创建一个对象,只能创建出一个对象的类被称为单例类
程序运行过程中,确保某一个类只有一个实例【对象】,不管在哪个模块获取这个类的对象,获取到的都是同一个对象。例如:一个国家只有一个主席,不管他在哪
单例设计模式的核心:一个类有且仅有一个实例,并且这个实例需要应用于整个程序中,该类被称为单例类
问题:验证两个变量中是否存储的是同一个对象
解决:地址
方式一:x1 is x2
方式二:id(x1) == id(x2)
2.应用场景
应用程序中描述当前使用用户对应的类 ———> 当前用户对于该应用程序的操作而言是唯一的——> 所以一般将该对象设计为单例
实际应用:数据库连接池操作 ——> 应用程序中多处地方连接到数据库 ———> 连接数据库时的连接池只需一个就行,没有必要在每个地方都创建一个新的连接池,这种也是浪费资源 ————> 解决方案也是单例
3.实现
3.1实现单例类方式一
# 1.普通类 class Person(): pass p1 = Person() p2 = Person() print(p1 is p2) # False print(id(p1) == id(p2)) # Flase print('*' * 50) # 2.单例类 ''' __new__ __init__ ''' class Person(): # 定义一个类属性,用于表示当前类可以创建的唯一的对象 # 因为此类属性无需在类的外面被访问修改,则设置为私有属性 __instance = None def __new__(cls, *args, **kwargs): print('new~~~') # 只要super().__new__(cls)被执行一次,则会创建出一个新的对象 # 判断__instance的值,如果为None,则重新赋值为对象并返回,如果非空则直接返回 if not cls.__instance: print('if~~~~') cls.__instance = super().__new__(cls) return cls.__instance def __init__(self,name,age): print('init~~~~',name,age) self.name = name self.age = age p1 = Person('张三',10) # 创建对象 p2 = Person('李四',20) # 获取第一次创建的对象,此处的李四和20相当于给对象的name和age属性重新赋值 print(p1 is p2) # True print(id(p1) == id(p2)) # True print(p1.name,p2.name) # 李四 p1.name = 'Jack' print(p1.name,p2.name)
3.2装饰器装饰类
.装饰器装饰类 def wrapper(cls): # cls表示需要被装饰的类 def inner(*args,**kwargs): c = cls(*args,**kwargs) # 类(),创建对象:调用类中的构造函数__new__,__init__,所以此处的参数需要和__init__中的参数保持一致 print('new~~~') # 新增的功能 return c return inner @wrapper # 调用外部函数wrapper class A(): def __init__(self,name,age): self.name = name self.age = age print(A) # <function wrapper.<locals>.inner at 0x000001DF7EDCC430> a1 = A('111',10) # 调用inner,a1中存储的是inner的返回值,为了符合最初创建对象的语法,则给inner设置返回值 print(a1)
3.3实现单例类方式二
def singleton(cls): # 定义一个函数作用域的变量,用于存储被装饰的类可以创建的唯一的对象 instance = None def get_instance(*args,**kwargs): nonlocal instance if not instance: instance = cls(*args, **kwargs) # 调用__init__ return instance return get_instance @singleton class Person(): def __init__(self,name,age): print('init~~~~~',name,age) self.name = name self.age = age p1 = Person('张三',10) # 调用get_instance p2 = Person('李四',20) # 调用get_instance print(p1 is p2) # True print(id(p1) == id(p2)) # True print(p1.name,p2.name) # 张三 p1.name = 'Jack' print(p1.name,p2.name)
3.4实现单例类方式三
def singleton(cls): # 定义一个函数作用域的字典变量,key:被装饰的类,value:唯一的对象 instance = {} def get_instance(*args,**kwargs): if not instance: # 向字典中添加键值对 instance[cls] = cls(*args, **kwargs) # 调用__init__ return instance[cls] return get_instance @singleton class Person(): def __init__(self,name,age): print('init~~~~~',name,age) self.name = name self.age = age p1 = Person('张三',10) # 调用get_instance p2 = Person('李四',20) # 调用get_instance print(p1 is p2) # True print(id(p1) == id(p2)) # True print(p1.name,p2.name) # 张三 p1.name = 'Jack' print(p1.name,p2.name)
补充说明
单例会带来全局状态,测试和并发场景更难控制。多数配置、连接或缓存需求也可以通过依赖注入或模块级对象处理。
本篇小结
理解单例的实现即可,实际项目应谨慎使用并明确生命周期。