单例模式
(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
什么是单例:
单例是指单个实例,指一个类只能有一个实例对象
为什么要使用单例?
当一个类的实例中的数据不会变化时使用单例,数据是不变的;在优酷系统中orm的书写有用到;
单例模式:
多次实例化结果指向同一个实例
开设单例模式的方法有许多种,常用的有以下5种方式:
第一种:基于classmethod
.绑定到类的方法:用classmethod装饰器装饰的方法。
特点:参数的第一个必须是cls表示当前类本身,使用类名来调用,调用时会自动传入类
相关知识点:
""" 1.类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法) 2.对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的 __call__ 方法 """
开设单例:
class Mysql(object): _instance = None 单例 def __init__(self, ip, port): self.ip = ip self.port = port @classmethod def singleton(cls): if not cls._instance: cls._instance = Mysql('127.0.0.1', 3306) return cls._instance obj1 = Mysql.singleton() obj2 = Mysql.singleton() print(obj1) print(obj2)
运行的结果:
第二种(基于装饰器),自定义的
def singleton(cls): # 该对象在类Mysql被装饰上singleton的时候就已经实例化完毕 _instance = cls('127.0.0.1',3306) def inner(*args,**kwargs): # 判断是否传入参数,传入参数表示要实例化新的,不传表示用默认的 if args or kwargs: obj = cls(*args,**kwargs) return obj return _instance return inner @singleton class Mysql: def __init__(self,ip,port): self.ip = ip self.port = port obj1 = Mysql() obj2 = Mysql() obj3 = Mysql() print(obj1,obj2,obj3)
运行的结果是得到指向的是同一个内存地址
第三种是基于元类的单例模式(type)
class MymetaClass(type): def __call__(self, *args, **kwargs): if not hasattr(self,'instance'): self.instance = super().__call__(*args,**kwargs) return self.instance class Mysql(metaclass=MymetaClass): def __init__(self,host,port): self.host = host self.port = port obj = Mysql('ajdak',213) obj1 = Mysql('asdasdas',134234) print(obj,obj1)
结果:
第四种(基于__new__)
元类中__new__
是用于创建类对象的 ,__init__
是用于初始化类的其他信息的.
我们知道,当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.__new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式
class Mysql(object): _instance = None def __init__(self,name): self.name = name def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = object.__new__(cls) return cls._instance obj = Mysql('egon') obj1 = Mysql('jason') print(id(obj),id(obj1))
第五种(基于模块)
其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc
文件,当第二次导入时,就会直接加载 .pyc
文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了
# 单独在一个py文件中定义一个类,并实例化一个对象,之后在其他文件导入这一对象,实现单例 class Singleton(object): def __init__(self,host,port): self.host = host self.port = port singleton = Singleton('127.0.0.1',3306)