线程锁、单例模式
在写自动化过程中发现有不少场景需要用到缓存;
在研究测开框架的过程中,发现用到了线程锁、单例模式
一、对方法的参数锁(防止多线程破坏单例模式)
给方法创建一个__lock__ 对象,并赋值线程锁
def synchronized(func): func.__lock__ = threading.Lock() def lock_func(*args, **kwargs): """with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作, 释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等""" with func.__lock__: return func(*args, **kwargs) return lock_func
二、单例模式(参考https://www.jianshu.com/p/6a1690f0dd00)
单例模式就是面向对象编程的一种设计模式,单例模式保证了在程序运行中该类只实例化一次,并且提供了一个全局访问点;
1、为什么Python模块就是天然的单例模式?
当我们使用 import A 这行代码导入模块A时,底层做了以下事情:
(1)检查模块A是否已经被加载到了sys.modules中,即检查字典sys.modules中是否有A这个key。
(sys.modules是一个将模块名称映射到已装载模块的全局字典。该字典在python启动后就存在于内存中。字典sys.modules对于导入模块起到了缓存的作用。当某个模块第一次导入,字典sys.modules将自动记录该模块。当第二次再导入该模块时,python会直接到字典中查找,从而加快了程序运行的速度。)
(2)如果 sys.modules 中找到了A这个key,那么说明这个模块已经装载过,则通过key获得了对应的< module A >对象。
如果 sys.modules 中没有找到A这个key,那么说明这个模块是全局第一次被导入,则执行下面的装载工作。在sys.modules中以A为key创建一个新的module对象(< module A >),此时< module A >的__dict__属性中还没有绑定模块A中的全局变量、函数、类。然后从sys.path目录中按照模块名称A查找模块文件,模块文件可以是py、pyc、pyd,找到后将模块编译、执行模块文件中的代码,为执行到的全局变量、函数、类分配内存,并其将绑定到的__dict__属性上。
(3)在当前命名空间中将< module A >这个对象赋值给变量A。
在程序运行期间模块A只装载一次,从而< module A >对象只有一个,无论import多少次,得到的都是同一个< module A >对象。这符合单例模式的定义,即单例对象的类只能允许一个实例存在。
2、使用装饰器
先放个链接,后面有空再看:https://blog.csdn.net/a1053904672/article/details/89106380
3、使用__new__实现单例模式,参考来源https://blog.csdn.net/qq_26442553/article/details/94393191
class MusicPlayer: # 定义类属性记录单例对象引用 instance = None def __new__(cls, *args, **kwargs): # 1. 判断类属性是否已经被赋值 if cls.instance is None: cls.instance = super().__new__(cls) # 2. 返回类属性的单例引用 return cls.instance print(id(MusicPlayer(1))) print(id(MusicPlayer(2)))
使用类名()创建对象的时候,python解释器首先会调用__new__方法为对象分配空间
__new__是一个由object基类提供的内置的静态方法,主要作用有两个:
1.在内存中为对象分配空间
2.返回对象的引用
python解释器获得对象的引用后,将引用作为第一个参数,传递给__init__方法
重写__new__方法的代码非常固定
一定要 return super().__new__(cls)
否则python解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法
注意:__new__是一个静态方法,在调用时需要主动传递cls参数