python设计模式之单例模式(一)
前言
单例模式是创建模式中比较常见和常用的模式,在程序执行的整个生命周期只存在一个实例对象。
系列文章
目录
简单理解
- 每个类创建实例化对象的时候,保证在同一个上下文环境中确保某一个类只有一个实例,减少内存的开销。
python实现方法
python类的实例是由__new__方法创建的,因此单例要在new方法上做文章。
class Test(object):
__instance = None
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance=object.__new__(cls) # 将实例对象用一个变量引用住,以后每次创建时直接返回该对象
return cls.__instance
def __init__(self):
pass
class Test(object):
__instance = None
__first_one = False
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance=object.__new__(cls)
return cls.__instance
def __init__(self, name):
if not self.__first_one: # 使用一个变量的状态来记录__init__的状态,保证只初始化一次,提高运行效率
self.__first_one = True
self.name = name
一般的应用场景
- 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;比如一个对象创建时有几十上百个属性需要初始化,而初始化参数又不变的;因为object._new_(cls)方法每执行一次就会在内存中创建一个新的实例。
class Test(object):
__instance = None
__first_one = False
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance=object.__new__(cls)
return cls.__instance
def __init__(self, name):
if not self.__first_one: # 使用一个变量的状态来记录__init__的状态,保证只初始化一次,提高运行效率
self.__first_one = True
self.name1 = name
....
self.name100 = "xxxx"
-
工具类对象;有时为了方便管理工具函数,会让工具函数变成某个类的实例方法,但是在调用的时候要先创建一个实例,所以这个实例可以是一个单例。
-
频繁访问数据库或文件的对象;由于涉及io操作,耗时较多,所以良好的做法是在内存中维护一个连接池,需要的时候返回一个连接对象。
连接mysql实例
# 以连接mysql为例
from pymysql import *
class MysqlManager(object):
pool = [] # 设置连接池
__instance = None
__first_one = False
count = 0
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
def __init__(self, host,port,database,user,password,charset='utf8',number=5):
if not self.__first_one:
self.__first_one = True
self.number = number
self.pool = [connect(host=host, port=port, database=database,
user=user, password=password, charset=charset) for i in range(number)]
def __enter__(self): # 上下文管理器返回一个连接对象
if self.count < self.number:
con = self.pool[self.count]
self.count += 1
return con
else:
self.count = 0
return self.pool[0]
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def get_cursor(self): # 直接得到一个游标
if self.count < self.number:
con = self.pool[self.count]
self.count += 1
return con.cursor()
else:
self.count = 0
return self.pool[0].cursor()
- 多线程需要相同的创建的对象,可以使用单例共享资源优化配置。
总结
-
python单例模式的实现原理主要是另__new__魔法方法和__init__魔法方法每次返回的对象不变即可;
-
单例模式主要用在当一些场景不关心实例的属性而只关系实例的方法,即业务需要使用对象的功能,对对象本身的属性不会去改变它。