Python3 & 使用__new__实现单例模式

2020-12-08  本文已影响0人  乘风破浪的姐姐

单例设计模式概念

设计模式,是对工作的总结和提练,目的是提高代码的可重用性及可靠性。
单例设计模式,是指让类创建的对象,在系统中只有 唯一的一个实例。且每一次执行 类名() 返回的对象,内存地址是相同的。这种模式一般应用在 例如:打印机,视频播放等应用上。

new 方法

使用 类名() 创建对象时,Python 的解释器 首先 会 调用 new 方法为对象 分配空间。new 是一个 由 object 基类提供的 内置的静态方法,主要作用有两个:

  1. 在内存中为对象 分配空间
  2. 返回 对象的引用
    示例:
class PrintPlayer(object):
    def __new__(cls, *args, **kwargs):
        print("__new__")

    def __init__(self):
        print("初始化打印机对象....")

prints = PrintPlayer()
print(prints)

输出结果:

__new__
None

可以看到,上述示例中,new没有返回对象的引用,所以在打印实例化对象时,返回了 None

正确的写法应该是

class PrintPlayer(object):
    def __new__(cls, *args, **kwargs):
        return super().__new__(cls)

    def __init__(self):
        print("初始化打印机对象....")

prints = PrintPlayer()
print(prints)

输出结果:

初始化打印机对象....
<__main__.PrintPlayer object at 0x000002329A47E7C0>

Python 中的单例模式

所谓单例,是让类在系统中创建唯一的一个实例,那么如何做到呢?
步骤分析:
1)定义一个 类属性,初始值是 None,用于记录 单例对象的引用
2)重写 new 方法
3)如果 类属性 is None,调用父类方法分配空间,并在类属性中记录结果
4)返回 类属性 中记录的 对象引用
代码:

class PrintPlayer(object):
    instance = None
    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls)

        return cls.instance

    def __init__(self):
        print("初始化打印机对象....")

prints1 = PrintPlayer()
print(prints1)

prints2= PrintPlayer()
print(prints2)

输出:

初始化打印机对象....
<__main__.PrintPlayer object at 0x000002776F59E7C0>
初始化打印机对象....
<__main__.PrintPlayer object at 0x000002776F59E7C0>

可以看出,在每次使用 类名() 创建对象时,Python 的解释器都会自动调用两个方法:new 分配空间,init 对象初始化。所以实例化两次,会调用init方法两次初始化。
那么如何让 初始化动作 只被 执行一次呢?

解决方法:
1)定义一个类属性 init_flag 标记是否 执行过初始化动作,初始值为 False
2)在 init 方法中,判断 init_flag,如果为 False 就执行初始化动作
3)然后将 init_flag 设置为 True
这样,再次 自动 调用 init 方法时,初始化动作就不会被再次执行 了
代码:

class PrintPlayer(object):
    instance = None
    init_flag = False
    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls)

        return cls.instance

    def __init__(self):
        if not PrintPlayer.init_flag :
            print("初始化打印机对象....")
            PrintPlayer.init_flag = True

prints1 = PrintPlayer()
print(prints1)

prints2= PrintPlayer()
print(prints2)

输出:

 初始化打印机对象....
<__main__.PrintPlayer object at 0x000001E8E23CE7C0>
<__main__.PrintPlayer object at 0x000001E8E23CE7C0>
上一篇下一篇

猜你喜欢

热点阅读