单例模式使用场景:
1、在程序中,多个模块中,使用该类的对象时:每个实例化对象都会有内存开销
2、日志收集器设置成单例模式:每个实例化日志对象后,每个日志对象会重复收集
3、数据库链接:1个脚本可能存在连接多次数据库,数据库最多允许多少个连接,在安装时有配置;
如果配置了100,当超出100后其他的对象连接不上,
使用单例模式,服务端数据库连接只有一个连接,在性能方面有个提升
案例一:实现单例模式
class Person(object):
__obj=None
def __new__(cls, *args, **kwargs):
if cls.__obj is not None:
cls.__obj=super().__new__(cls)
#cls.obj=object.__new__(cls)
return cls.__obj
if __name__ == '__main__':
p=Person()
p1=Person()
p2=Person()
print(id(p))
print(id(p1))
print(id(p2))
执行结果:
140711521459416
140711521459416
140711521459416
案例二:通过装饰器实现单例模式,只要任意一个类使用该装饰器装饰,那么就会变成一个单例模式的类
1、用函数装饰器实现
def Person(func):
isinstance={}
def wrapper(*args,**kwargs):
if func in isinstance:
return isinstance[func]
else:
isinstance[func]=func(*args,**kwargs)
return isinstance[func]
return wrapper
@Person #Demo=Person(Demo)
class Demo:
print('开始执行')
if __name__ == '__main__':
d1=Demo()
d2=Demo()
d3=Demo()
print(id(d1))
print(id(d2))
print(id(d3))
开始执行
2545623642016
2545623642016
2545623642016
2、用类装饰器实现
class Person:
obj={}
def __init__(self,func):
self.func=func
def __call__(self, *args, **kwargs):
if self.func not in self.obj:
self.obj[self.func]=self.func(*args,**kwargs)
return self.obj[self.func]
else:
return self.obj[self.func]
@Person #Demo=Person(Demo)
class Demo:
print('开始执行')
if __name__ == '__main__':
d1=Demo()
d2=Demo()
d3=Demo()
print(d1)
print(d2)
print(d3)
开始执行
<main.Demo object at 0x000001F0B6802F70>
<main.Demo object at 0x000001F0B6802F70>
<main.Demo object at 0x000001F0B6802F70>
案例三:请实现一个类,前五次创建对象,每次都可以返回一个新的对象,第六次开始,每次创建,都随机返回前5个对象中的一个
import random
class Person:
obj_list=[]
def __new__(cls, *args, **kwargs):
if len(cls.obj_list) < 5:
cls.obj=super().__new__(cls)
cls.obj_list.append(cls.obj)
return cls.obj
else:
return random.choice(cls.obj_list)
if __name__ == '__main__':
p=Person()
p1=Person()
p2=Person()
p3=Person()
p4=Person()
p5=Person()
p6=Person()
print(id(p))
print(id(p1))
print(id(p2))
print(id(p3))
print(id(p4))
print(id(p5))
print(id(p6))