python学习第六天——单例

设计模式:就是经过前人总结提炼,形成对某一特殊问题的成熟解决方案,不同问题提供不同解决套路。
单例:目的时让类创建的对象在系统中只有一个实例,每一次执行类名()返回的对象,内存地址是相同的,即让类创建的对象在系统中只有一个实例。
原理:使用类名()创建一个对象时,python默认完成两件事情。第一步,应用__new__为对象创建一个内存空间(__new__是由object基类创建的内置静态方法),并返回对象的引用。接下来第二步就是将该引用传递给__init__的第一个参数,__init__开始定义实例属性。

cls是代表这个类, self是用来代表这个类的实例

学习new是为了对分配空间的方法进行改造

首先要明确为什么要重写new:object中自带new方法为实例分配内存空间并返回引用,但是不能实现让类创建的对象在系统中只有一个实例。因此,要重写new方法,使让类创建的对象在系统中只有一个实例。如果不重写new方法,使用基类object自带new方法,则当用类名创建多个实例时会给不同实例分配不同内存空间。

例如:

class Music_player(object):
    def __init__(self):
        print("初始化播放器")
player1 = Music_player()
print(player1)
player2 = Music_player()
print(player2)

输出结果为:

初始化播放器
<__main__.Music_player object at 0x000002280B710908>
初始化播放器
<__main__.Music_player object at 0x000002280B7109E8>

不仅多个实例时会给不同实例分配不同内存空间,而且还会调用两次初始化,这是不被允许的,接下来会慢慢改进。

**重写__new__方法:(为单例做铺垫)**注意:一定要返回对象引用!

实例:

class Music_player(object):
    def __new__(cls, *args, **kwargs):
        print("分配空间")
        #分配内存空间
        #调用父类中的方法
        instance = super().__new__(cls)
        #返回对象的引用
        return instance
    def __init__(self):
        print("播放器初始化")
player = Music_player()
print(player)

输出结果:

分配空间
播放器初始化
<__main__.Music_player object at 0x0000025993780908>

注意:在观看视频时,对于super().new(cls)中的参数,大家又有不同的看法。__new__方法, 是新式类用来创建实例使用的, 传入的cls就是用来给object.__new__创建实例使用的参数, 如果没有传入cls, object根本不知道创建什么样的实例.__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供.
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值

单例:

1.定义一个类属性,初始值为None,用于记录单例对象的引用。
20重写__new__方法
3.如果类属性is None,调用父类方法分配空间,并在类属性中记录结果。
4.返回类属性中记录的结果。
给创建的类的__new__中增加了判断条件。若类未被初始化,就没有实例获得内存区域,第一个实例被初始化后,第一个实例有了内存地址,就把这个地址赋给instance,之后的所有实例都使用instance中的地址。
实例:

class Music_player(object):
    #记录第一个被创建的引用
    instance = None
    def __new__(cls, *args, **kwargs):
        #1.判断雷
        #1.类属性是否为空对象,是空对象说明第一个对象还未被创建
        if cls.instance is None:
            #2.如果对象未被创建,调用父类方法,为第一个对象分配空间
            cls.instance = super().__new__(cls)
        #3.反回类属性保存的对象引用
        return cls.instance
player1 = Music_player()
print(player1)
player2 = Music_player()
print(player2)

输出结果:

<__main__.Music_player object at 0x000001CB9B8254A8>
<__main__.Music_player object at 0x000001CB9B8254A8>

改进:使初始化制备调用一次。

原理:定义类属性init_flag记录初始化是否被调用,将init_flag初始化为False,表示对象还未被初始化。在__init__函数中,判断init_flag,如果为True,则return,不再执行初始化;否则执行初始化动作。
实例:

class Music_player(object):
    #记录第一个被创建的引用
    instance = None
    init_flag = False
    def __new__(cls, *args, **kwargs):
        #1.判断雷
        #1.类属性是否为空对象,是空对象说明第一个对象还未被创建
        if cls.instance is None:
            #2.如果对象未被创建,调用父类方法,为第一个对象分配空间
            cls.instance = super().__new__(cls)
        #3.反回类属性保存的对象引用
        return cls.instance
    def __init__(self):
        #判断是否执行过初始化()
        if Music_player.init_flag:
            return
        # 如果没有执行过,执行初始化动作
        print("初始化播放器")
        #否则,修改类属性的标记
        Music_player.init_flag = True
player1 = Music_player()
print(player1)
player2 = Music_player()
print(player2)

输出结果:

初始化播放器
<__main__.Music_player object at 0x000001DAE2940908>
<__main__.Music_player object at 0x000001DAE2940908>

初始化动作只执行了一次。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值