单例模式的四种方式

一、内容

  • 保证一个类只有一个实例,并提供一个访问它的全局访问点

二、角色

  • 单利

三、使用场景

  • 当类只有一个实例而且客户可以从一个众所周知的访问点访问它时
  • 比如:数据库链接、Socket创建链接

四、优点

  • 对唯一实例的受控访问
  • 单利相当于全局变量,但防止了命名空间被污染

与单利模式功能相似的概念:全局变量、静态变量(方法)

试问?为什么用单例模式,不用全局变量呢?

  答、全局变量可能会有名称空间的干扰,如果有重名的可能会被覆盖

五、单例模式的四种实现方式

1、文件导入的形式(常用)

1 s1.py 2 3 class Foo(object): 4 def test(self): 5 print("123") 6 7 v = Foo() 8 #v是Foo的实例 9 10 s2.py 11 from s1 import v as v1 12 print(v1,id(v1)) #<s1.Foo object at 0x0000000002221710> 35788560 13 14 from s1 import v as v2 15 print(v1,id(v2)) #<s1.Foo object at 0x0000000002221710> 35788560 16 17 # 两个的内存地址是一样的 18 # 文件加载的时候,第一次导入后,再次导入时不会再重新加载。

2、基于类实现的单例模式

1 # ======================单例模式:无法支持多线程情况=============== 2 3 class Singleton(object): 4 5 def __init__(self): 6 import time 7 time.sleep(1) 8 9 @classmethod 10 def instance(cls, *args, **kwargs): 11 if not hasattr(Singleton, "_instance"): 12 Singleton._instance = Singleton(*args, **kwargs) 13 return Singleton._instance 14 15 import threading 16 17 def task(arg): 18 obj = Singleton.instance() 19 print(obj) 20 21 for i in range(10): 22 t = threading.Thread(target=task,args=[i,]) 23 t.start() 24 25 26 # ====================单例模式:支持多线程情况================、 27 28 import time 29 import threading 30 class Singleton(object): 31 _instance_lock = threading.Lock() 32 33 def __init__(self): 34 time.sleep(1) 35 36 @classmethod 37 def instance(cls, *args, **kwargs): 38 if not hasattr(Singleton, "_instance"): 39 with Singleton._instance_lock: #为了保证线程安全在内部加锁 40 if not hasattr(Singleton, "_instance"): 41 Singleton._instance = Singleton(*args, **kwargs) 42 return Singleton._instance 43 44 45 def task(arg): 46 obj = Singleton.instance() 47 print(obj) 48 for i in range(10): 49 t = threading.Thread(target=task,args=[i,]) 50 t.start() 51 time.sleep(20) 52 obj = Singleton.instance() 53 print(obj) 54 55 56 # 使用先说明,以后用单例模式,obj = Singleton.instance() 57 # 示例: 58 # obj1 = Singleton.instance() 59 # obj2 = Singleton.instance() 60 # print(obj1,obj2) 61 # 错误示例 62 # obj1 = Singleton() 63 # obj2 = Singleton() 64 # print(obj1,obj2)

3、基于__new__实现的单例模式

1 # =============单线程下执行=============== 2 import threading 3 class Singleton(object): 4 5 _instance_lock = threading.Lock() 6 def __init__(self): 7 pass 8 9 def __new__(cls, *args, **kwargs): 10 if not hasattr(Singleton, "_instance"): 11 with Singleton._instance_lock: 12 if not hasattr(Singleton, "_instance"): 13 # 类加括号就回去执行__new__方法,__new__方法会创建一个类实例:Singleton() 14 Singleton._instance = object.__new__(cls) # 继承object类的__new__方法,类去调用方法,说明是函数,要手动传cls 15 return Singleton._instance #obj1 16 #类加括号就会先去执行__new__方法,在执行__init__方法 17 # obj1 = Singleton() 18 # obj2 = Singleton() 19 # print(obj1,obj2) 20 21 # ===========多线程执行单利============ 22 def task(arg): 23 obj = Singleton() 24 print(obj) 25 26 for i in range(10): 27 t = threading.Thread(target=task,args=[i,]) 28 t.start() 29 30 31 # 使用先说明,以后用单例模式,obj = Singleton() 32 # 示例 33 # obj1 = Singleton() 34 # obj2 = Singleton() 35 # print(obj1,obj2)

4、基于metaclass(元类)实现的单

1 """ 2 1.对象是类创建,创建对象时候类的__init__方法自动执行,对象()执行类的 __call__ 方法 3 2.类是type创建,创建类时候type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法) 4 5 # 第0步: 执行type的 __init__ 方法【类是type的对象】 6 class Foo: 7 def __init__(self): 8 pass 9 10 def __call__(self, *args, **kwargs): 11 pass 12 13 # 第1步: 执行type的 __call__ 方法 14 # 1.1 调用 Foo类(是type的对象)的 __new__方法,用于创建对象。 15 # 1.2 调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。 16 obj = Foo() 17 # 第2步:执行Foo的 __call__ 方法 18 obj() 19 """ 20 21 # ===========类的执行流程================ 22 class SingletonType(type): 23 def __init__(self,*args,**kwargs): 24 print(self) #会不会打印? #<class '__main__.Foo'> 25 super(SingletonType,self).__init__(*args,**kwargs) 26 27 def __call__(cls, *args, **kwargs): #cls = Foo 28 obj = cls.__new__(cls, *args, **kwargs) 29 obj.__init__(*args, **kwargs) 30 return obj 31 32 33 class Foo(metaclass=SingletonType): 34 def __init__(self,name): 35 self.name = name 36 def __new__(cls, *args, **kwargs): 37 return object.__new__(cls, *args, **kwargs) 38 ''' 39 1、对象是类创建的,创建对象时类的__init__方法会自动执行,对象()执行类的__call__方法 40 2、类是type创建的,创建类时候type类的__init__方法会自动执行,类()会先执行type的__call__方法(调用类的__new__,__init__方法) 41 Foo 这个类是由SingletonType这个类创建的 42 ''' 43 obj = Foo("hiayan") 44 45 46 # ============第三种方式实现单例模式================= 47 import threading 48 49 class SingletonType(type): 50 _instance_lock = threading.Lock() 51 def __call__(cls, *args, **kwargs): 52 if not hasattr(cls, "_instance"): 53 with SingletonType._instance_lock: 54 if not hasattr(cls, "_instance"): 55 cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) 56 return cls._instance 57 58 class Foo(metaclass=SingletonType): 59 def __init__(self,name): 60 self.name = name 61 62 63 obj1 = Foo('name') 64 obj2 = Foo('name') 65 print(obj1,obj2)

六、单例模式的应用(会在数据库连接池中用到单例模

pool.py

1 import pymysql 2 import threading 3 from DBUtils.PooledDB import PooledDB 4 5 class SingletonDBPool(object): 6 _instance_lock = threading.Lock() 7 8 def __init__(self): 9 self.pool = PooledDB( 10 creator=pymysql, # 使用链接数据库的模块 11 maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数 12 mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建 13 14 maxcached=5, # 链接池中最多闲置的链接,0和None不限制 15 maxshared=3, 16 # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。 17 blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错 18 maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 19 setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."] 20 ping=0, 21 # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always 22 host='127.0.0.1', 23 port=3306, 24 user='root', 25 password='123', 26 database='pooldb', 27 charset='utf8' 28 ) 29 30 def __new__(cls, *args, **kwargs): 31 if not hasattr(SingletonDBPool, "_instance"): 32 with SingletonDBPool._instance_lock: 33 if not hasattr(SingletonDBPool, "_instance"): 34 SingletonDBPool._instance = object.__new__(cls, *args, **kwargs) 35 return SingletonDBPool._instance 36 37 def connect(self): 38 return self.pool.connection()

app.py

1 from pool import SingletonDBPool 2 3 def run(): 4 pool = SingletonDBPool() 5 conn = pool.connect() 6 # xxxxxx 7 cursor = conn.cursor() 8 cursor.execute("select * from td where id=%s", [5, ]) 9 result = cursor.fetchall() # 获取数据 10 cursor.close() 11 conn.close() 12 13 if __name__ == '__main__': 14 run()

额外补充的一种用装饰器实现的单利模式

1 # 2 def wrapper(cls): 3 instance = {} 4 def inner(*args,**kwargs): 5 if cls not in instance: 6 instance[cls] = cls(*args,**kwargs) 7 return instance[cls] 8 return inner 9 10 @wrapper 11 class Singleton(object): 12 def __init__(self,name,age): 13 self.name = name 14 self.age = age 15 16 obj1 = Singleton('haiyan',22) 17 obj2 = Singleton('xx',22) 18 print(obj1) 19 print(obj2)

 

分类: flask

归类 : Python学习

原文地址:https://www.cnblogs.com/lz1996/p/11552161.html