目标

  • 单例设计模式
  • _ _new__方法
  • python中的单例

01 _ _new__方法

  • _ new__方法 是一个由object基类提供的内置的静态方法,主要作用有两个:
    1、在内存中为对象 分配空间
    2、返回 对象的引用
    使用 类名() 创建对象时,python的解释器 首先会调用
    new__方法为对象分配空间
    python的解释器获得对象的引用后(为对象分配的内存空间地址),将引用作为第一个参数传递给
    _init__方法

重写 _ _new__方法的代码非常固定!

重写_ _new__方法一定要加上 return super().__new__(cls)

否则python 的解释器得不到分配了空间的 对象引用,就不会掉用对象的初始化方法
注意:_ _new__方法是一个静态方法,调用时需要主动传递 cls 参数????

class MusicPlayer(object):
    count = 666
    def __new__(cls, *args, **kwargs):
        print("创建对象,分配空间")
        instance = super().__new__(cls)
        return instance

    def __init__(self):
        print("播放器初始化")


player = MusicPlayer()
print(player)

02 单例设计模式

  • 设计模式:前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对某一特定问题的成熟的解决方案。使用设计模式 是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
  • 单例设计模式:
    目的:让类创建的对象在系统中只有唯一的一个实例
    每一次执行 类名()返回的对象,内存地址是相同的

单例设计模式的应用场景:

  • 音乐播放对象
  • 回收站对象
  • 打印机对象
  • ......

03 python中的单例

单例——让类创建的对象,在系统中 只有唯一的一个实例。
定义一个类属性,初始值是None,用于记录 单例对象的引用(内存地址)。
重写_ _new__方法
如果类属性 is None ,调用父类方法分配空间,并在类属性中记录结果
返回类属性中记录的对象引用(内存地址)
图片说明

代码:

class MusicPlayer(object):
    # 记录第一个被创建对象的引用
    instance = None
    def __new__(cls, *args, **kwargs):
        # 1、判断类属性是否是空对象
        if cls.instance is None:
            # 2、调用父类方法,为第一个对象分配空间
            cls.instance = super().__new__(cls)
        # 返回类属性保存的对象引用
        return cls.instance

player1 = MusicPlayer()
print(player1)
player2 = MusicPlayer()
print(player2)

04 改进——只执行一次初始化工作
我们知道,在每次使用 类名()创建对象时,python的解释器都会自动调用两个方法:

  • _ new_ 方法 分配空间
  • _ init_ 方法 对象初始化

上一小节对 _ new__ 方法改造之后,每次都会得到 第一次被创建对象的引用。但是,初始化方法 _ init_ 方法还是会每次调用。
需求:让初始化动作只被执行一次。
解决:我们不能阻止每次创建对象时
init__ 方法的自动调用,但是可以:
定义一个类属性 init_flag 标记是否执行过初始化动作,初始值为False
init__ 方法中判断init_flag,如果为False 就执行初始化动作,然后将init_flag设置为True
这样,再次调用
init_ 方法时,初始化动作就不会再次被执行了。

代码:

class MusicPlayer(object):
    # 记录第一个被创建对象的引用
    instance = None
    # 记录是否执行过初始化动作
    init_flag = False
    def __new__(cls, *args, **kwargs):
        # 1、判断类属性是否是空对象
        if cls.instance is None:
            # 2、调用父类方法,为第一个对象分配空间
            cls.instance = super().__new__(cls)
        # 返回类属性保存的对象引用
        return cls.instance

    def __init__(self):
        # 判断是否执行过初始化动作
        if MusicPlayer.init_flag :
            return
        # 如果没有执行,再执行初始化动作
        print("初始化播放器")
        # 修改类属性的标记
        MusicPlayer.init_flag = True


player1 = MusicPlayer()
print(player1)
player2 = MusicPlayer()
print(player2)