一、理解单例模式
确保类有且只有一个特定类型的对象,并提供全局访问点,单例模式通常用于下列情形,例如日志记录或数据库操作等,避免对同一资源请求的相互冲突。
单例的模式的意图如下:
- 确保类有且只有一个对象被创建。
- 为对象提供一个访问点,以使程序可以全局访问该对象。
- 控制共享资源的并行访问。
实现单例模式的一个简单方法是,使构造函数私有化,并创建一个静态方法来完成对象的初始化。这样,对象将在第一次调用时创建,此后,这个类将返回同一个对象。然后在python中构造函数是无法私有化的,因此需要使用其他方式进行创建。
二、实现
1、基于__new__方法创建单例
__new__方法是先于__init__方法执行,主要用于创建对象,在完成单例模式时,主要是:只允许单例类生成一个实例;如果已经有一个实例了,重复提供同一个对象。这样保证每一次实例化类只提供一个对象。
class SingleTon(object): def __new__(cls, *args, **kwargs): if not hasattr(cls,"instance"): cls.instance = super(SingleTon,cls).__new__(cls, *args, **kwargs) return cls.instance s=SingleTon() print(s) s1=SingleTon() print(s1) ###输出########### #<__main__.SingleTon object at 0x0000000000656828> #<__main__.SingleTon object at 0x0000000000656828>
上面是通过覆盖__new__的方法创建对象的,对象s就是由__new__方法创建的,但是在创建之前会先检查cls中是否已经有一个对象(instance就是对象),如果没有就创建一个实例,如果已经存在,就将已经存在的实例进行返回。
s1对象在使用__new__方法创建时,会通过hasattr属性检查是否已经存在对象实例,此时已经存在s的实例,所以将s的实例地址返回给s1。
2、基于getInstance创建单例
为了避免对内存造成浪费,直到需要实例化该类的时候才将其实例化,所以用getInstance来获取该对象。
class SingleTon(object): _instance=None def __init__(self): if not SingleTon._instance: print("没有创建对象") else: print("已经创建对象",self.getInstance()) @classmethod def getInstance(cls): if not cls._instance: cls._instance=SingleTon() return cls._instance s=SingleTon() #并没有创建对象 SingleTon.getInstance() #创建了对象 s1=SingleTon() #对象已经存在 #####################输出############ #没有创建对象 #没有创建对象 #已经创建对象 <__main__.SingleTon object at 0x0000000000676898>
当执行s=SingleTon()执行了__init__方法,然而并没有创建对象,真正创建对象的是在SingleTon.getInstance(),这样每次在获取对象时就通过这个静态方法获取,不需要使用__new__方法来创造对象。
3、基于模块级别的单例模式
python导入模块的行为决定了每一个模块都是单例,因为,python在导入模块时会检查模块是否已经导入,如果没有导入,它会进行导入并且实例化,如果已经导入则会返回该模块的对象。
因此,当模块被导入的时候,它就会被初始化。然而,当同一个模块被再次导入的时候,它不会再次初始化,因为单例模式只能有一个对象,所以,它会返回同一个对象。
使用方式:
- 在一个py文件中写入类并且实例化
class AdminSite(object): def __init__(self): pass site=AdminSite()
- 在另一个py文件中导入该类对象
from base_moudle.base import site print(site) #<base_moudle.base.AdminSite object at 0x0000000000D3AE80>
4、基于元类创建单例
在python中 一切皆对象,由class关键字创建的类也应该是一个对象,那么,既然是对象,它也应该是由类来创建的,这个类就叫做元类(type)。当通过一个元类来创建一个类时,比如当使用类A创建一个类时,pytno通过A=type(name,bases,dict)创建它。
- name:这是类的名称。
- base:这是基类。
- dict:这是属性变量。
比如使用元类创建一个类:
class MyString(type):#继承type才是一个元类 def __call__(self, *args, **kwargs): return type.__call__(self,*args, **kwargs) class String(metaclass=MyString): def __init__(self,x): self.x=x s=String("abggd")
当需要创建对象时,将调用__call__方法,也就是说对象()触发__call__方法的执行,当对String类进行实例化时,实际是MyString元类的对象进行实例化,这会触发__call__方法的运行,它的返回值就是实例化后的结果的接收值,这意味者元类控制着对象的实例化。
同样的,也就可以利用以上的思路,进行单例模式的实现,为了控制类的创建和初始化,元类将覆盖__new__以及__init__方法。
class MetaSingleTon(type): _instance={} def __call__(self, *args, **kwargs): #self指代的是传过来的类 AdminSite if self not in self._instance: self._instance[self]=super(MetaSingleTon,self).__call__( *args, **kwargs) return self._instance[self] class AdminSite(metaclass=MetaSingleTon): pass a1=AdminSite() #相当于执行元类中的__call__方法,__call__的返回值是什么a1就是什么 print(a1) a2=AdminSite() print(a2) ########输出########### #<__main__.AdminSite object at 0x0000000000666CC0> #<__main__.AdminSite object at 0x0000000000666CC0>
单例模式可以应用于多种场景,这里提供应用于数据库层面的,保证数据库操作一致性以及提高内存利用率。
import pymysql class MetaSingleTon(type): _instance={} def __call__(self, *args, **kwargs): #self指代的是传过来的类 AdminSite if self not in self._instance: self._instance[self]=super(MetaSingleTon,self).__call__( *args, **kwargs) return self._instance[self] class DataBase(metaclass=MetaSingleTon): connection=None def connect(self): if self.connection is None: self.connection=pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root', db='test', charset='utf8') self.cursor=self.connection.cursor() return self.cursor def excute(self,sql): pass def close(self): self.connect().close() self.connection.close() db1=DataBase() db2=DataBase() print(db1) print(db2) #########################输出################ #<__main__.DataBase object at 0x0000000000DF6A90> #<__main__.DataBase object at 0x0000000000DF6A90>
5、Monostate单例模式
它与Singleton单例模式是有不同之处的,Singleton关注的是一个类有且只有一个对象,而Monostate关注的则是一个类不管有多少个对象,所有的对象只有一个状态,因此它也被称为单态模式。那么它是如何实现这种模式呢?
class Borg: __shared_state={} def __init__(self): self.x=3 self.__dict__=self.__shared_state b1=Borg() b2=Borg() b2.x=4 print(b1.__dict__) print(b2.__dict__) ######输出########### #{'x': 4} #{'x': 4}
将__shared_state变量作为一个中间变量,并且赋值给python中存储类所有对象状态的__dict__变量,这在实例后,会产生两个不同的对象,但是b1.__dict__和b2.__dict__都指向了__shared_state的内存地址。
另外还可以通过__new__来实现单态模式:
class Borg: __shared_state = {} def __new__(cls, *args, **kwargs): obj=super(Borg,cls).__new__(cls, *args, **kwargs) obj.__dict__ = obj.__shared_state return obj