python单例模式

需要掌握:设计模式-单例模式

概述

本文讲解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__()方法

实现单例模式

在上面的测试类基础上实现:

  1. 定义类属性instance=None
  2. 重写__new__()方法,如果类属性instance为None,就创建对象,并让instance指向该对象
  3. 返回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)

通过打印结果可知:

  1. 对象的内存地址相同,说明是同一个对象
  2. 虽然只创建一个对象,但每次都调用__init__()方法了,这是不合理的

只执行一次__init__()方法

  1. __init__()方法中判断当前实例是否有_is_init实例属性
  2. 如果有该属性就不在往下运行
  3. 如果没有该属性,就给当前实例绑定_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)

总结:
在实现简单功能时,单例模式和类方法可以实现同样的功能


原文出处:/show_1EF3XiVFI0Qd.html