python3实现单例模式
单例模式指确保某个类在整个系统中只存在一个实例的一种设计模式
使用单例模式的好处:
1、每个实例都会占用一定的内存资源,且初始化实例时会影响运行性能,所以当整个系统只需一个实例时,使用单例模式不仅可减少资源占用,而且因为只初始化一次,还可以加快运行性能。例如当程序通过一个类来读取配置信息,而程序多个地方需要使用配置信息,这时整个程序运行过程中只需一个实例对象即可,可减少占用内存资源,同时还可以保证程序在多处地方获取的配置信息一致。
2、使用单例模式可进行同步控制,计数器同步、程序多处读取配置信息这些情景下若只存在一个实例,即可保证一致性。
在python中,一般可使用一下4种方式实现单例模式:
1、通过模块调用
2、使用__new__方法
3、使用装饰器
4、使用元类(metaclass)
一、通过模块调用
做法:将需要实现单例的类写在模块文件中,然后通过import引入该模块,即可得到单例对象。
原理:在python3中,首次导入模块文件时,会在程序目录下的__pycache__目录中生成pyc文件,之后再导入时,将直接加载pyc文件。从而实现单例。
实现代码:
- module_demo.py
class singleton_cal: def foo(self): pass export_singleton = singleton_cal()
- use_module.py
from module_demo import export_singleton a = export_singleton from module_demo import export_singleton b = export_singleton print(a == b) print(id(a) == id(b))
可发现,多次调用/导入模块,使用的都是同一个实例对象
二、使用__new__方法
_new__与_init__的区别:
__new\:创建实例对象时调用的构造方法
_init_:初始化方法,用于设置实例的相关属性
python创建实例时,会先调用__new__构造方法,然后使用__init__进行实例初始化。
我们可以通过__new__来影响实例的创建,从而实现单例。
实现代码:
- use_new.py
class Singleton(object):
__instance = None
def __new__(cls,*args,**kwargs):
if not cls. __instance:
cls.__instance = super().__new__(cls,*args,**kwargs)
return cls.__instance
a = Singleton()
b = Singleton()
print(a == b)
print(id(a) == id(b))
上面代码中,声明了一个私有类变量__instance,当__instance不为None时,代表系统中已有实例,直接返回该实例,若__instance为None时,表示系统中还没有该类实例,则创建新实例并返回。
三、使用装饰器
- use_decorator.py
from functools import wraps
def singleton(cls):
instances = {}
@wraps(cls)
def getinstance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return getinstance
@singleton
class singleCls(object):
def foo(self):
pass
a = singleCls()
b = singleCls()
print(a == b)
print(id(a) == id(b))
只有当第一次调用singleCls时,装饰器才会从instances={}开始执行,之后调用singleCls时,都只执行getinstance函数,这是装饰器的特性,利用这个特性,当我们多次调用singleCls时,在getinstance函数中判断该类是否存在于instances字典中,若不存在,则创建该类实例并加入instances字典中,并返回字典中该类的实例;若存在,则直接返回字典中该类的实例。可利用该装饰器为多个类实现单例。
四、使用元类(metaclass)
元类创建了所有的类型对象(包括object对象),系统默认的元类是type。
实例,类,父类,元类的关系可表示为下图
元类中的__call方法,在已该类为元类的类创建实例时调用,例如:类A以类B为元类,当A创建实例时,B中的\call将会被调用。利用\call__可实现对实例创建的控制。
实现代码:
- use_metaclass.py
class SingletonMeta(type):
__instance = None
def __call__(cls,*args,**kwargs):
if not cls.__instance:
cls.__instance = type.__call__(cls,*args,**kwargs)
return cls.__instance
class myclass(metaclass = SingletonMeta):
def foo(self):
pass
a = myclass()
b = myclass()
print(a==b)
print(id(a)==id(b))
自定义元类时,通常继承自type,声明一个私有类变量__instance保存类实例,当__instance为None时,调用type的__call__方法为类创建实例,保存到__instance并返回;若__instance不为None,则直接返回__instance,不重新创建实例。
欢迎扫码关注公众号“KeepCode”,分享更多技术好文,并提供技术电子书籍免费下载,每天进步一点点~~~~
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341