需要掌握:设计模式-单例模式
概述
本文讲解python的 单例模式 实现
python中实现 单例模式 的方式有若干种,本文讲解类的内置方法__new__()
重写__new__()方法
通过写一个简单的测试类,理解该方法
class Test:
def __new__(cls,*args,**kwargs):
instance=super().__new__(cls)
print(instance)
return instance
def __init__(self):
print(self)
t=Test()
t=Test()
t=Test()
注意:
__new__()方法是静态方法,调用时必须手动传递cls参数
从打印的结果可知,对象的内存地址是一样的,说明__new__()方法返回的对象,作为参数传递给__init__()方法
每次创建对象都会调用__init__()方法
实现单例模式
在上面的测试类基础上实现:
- 定义类属性
instance=None - 重写
__new__()方法,如果类属性instance为None,就创建对象,并让instance指向该对象 - 返回
instance
代码如下:
class Test:
_instance=None
def __new__(cls,*args,**kwargs):
if cls._instance==None:
cls._instance=super().__new__(cls)
print("__new__()方法:",cls._instance)
return cls._instance
def __init__(self):
print("__init__()方法:",self)
onb=Test()
print(onb)
onb=Test()
print(onb)
onb=Test()
print(onb)
通过打印结果可知:
- 对象的内存地址相同,说明是同一个对象
- 虽然只创建一个对象,但每次都调用
__init__()方法了,这是不合理的
只执行一次__init__()方法
__init__()方法中判断当前实例是否有_is_init实例属性- 如果有该属性就不在往下运行
- 如果没有该属性,就给当前实例绑定
_is_init属性,并且往下运行初始化的代码
代码如下:
def __init__(self):
if hasattr(self,"_is_init"):
return
self._is_init=True
#下面是初始化的代码
print("__init__()方法:",self)
再次运行,就只执行一次__init__()方法
完整代码
class Test:
_instance=None
def __new__(cls,*args,**kwargs):
if cls._instance==None:
cls._instance=super().__new__(cls)
print("__new__()方法:",cls._instance)
return cls._instance
def __init__(self):
if hasattr(self,"_is_init"):
return
self._is_init=True
#下面是初始化的代码
print("__init__()方法:",self)
使用单例类:
onb=Test()
print(onb)
onb=Test()
print(onb)
onb=Test()
print(onb)
练习
实现OrderNumberGenerater类,该类为单例模式,通过调用方法generate()生成订单编号,编号前8位为YYYYmmdd,后8位为流水号,流水号不足8位前面补0,第二天流水号从1开始。如:2018111500000001
代码如下:
from datetime import datetime
import time
class OrderNumberGenerater:
_instance=None
def __new__(cls,*args,**kwargs):
if cls._instance==None:
cls._instance=super().__new__(cls)
print("__new__()方法:",cls._instance)
return cls._instance
def __init__(self):
if hasattr(self,"_is_init"):
return
self._is_init=True
#下面是初始化的代码
print("__init__()方法:",self)
#定义上一次日期,用于比较是否变动
self._last_date=""
#流水号
self._num=1
def generate(self):
date=datetime.strftime(datetime.today(),"%Y%m%d")
#日期没变动,流水号加1
if date==self._last_date:
self._num+=1
else:
self._num=1
self._last_date=date
#不足8位补0
order_num="%s%08d"%(date,self._num)
return order_num
onb=OrderNumberGenerater()
print(onb)
onb=OrderNumberGenerater()
print(onb)
onb=OrderNumberGenerater()
print(onb)
while True:
print(onb.generate())
#休眠1秒钟,并且修改系统日期,并查看流水号是否从1开始
time.sleep(1)
练习2:
不用单例模式,通过类属性、类方法实现上面的功能
#coding=utf-8
from datetime import datetime
import time
class OrderNumberGenerater:
_last_date=''
_num=1
@classmethod
def generate(cls):
date=datetime.strftime(datetime.today(),"%Y%m%d")
#日期没变动,流水号加1
if date==cls._last_date:
cls._num+=1
else:
cls._num=1
cls._last_date=date
#不足8位补0
order_num="%s%08d"%(date,cls._num)
return order_num
print(OrderNumberGenerater.generate())
print(OrderNumberGenerater.generate())
print(OrderNumberGenerater.generate())
while True:
print(OrderNumberGenerater.generate())
#休眠1秒钟,并且修改系统日期,并查看流水号是否从1开始
time.sleep(1)
总结:
在实现简单功能时,单例模式和类方法可以实现同样的功能