Fork me on GitHub

【进阶12】【自学笔记】Python单例模式实现的几种方式

一、单例模式定义

单例模式是一种常用的创建型设计模式,它保证一个类只有一个实例,并提供一个全局的访问点。

二、实例展示

实例1:

class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

在这个示例中,我们定义了一个名为 Singleton 的类,其中包含了一个类变量 _instance,初始值为 None。在 __new__ 方法中,我们首先检查 _instance 变量是否为 None,如果是,则说明当前尚未创建过该类的实例,我们调用父类 super().__new__(cls) 创建一个新的实例,并将其保存在 _instance 中;否则,直接返回已存在的实例。

使用时,我们可以像下面这样来创建 Singleton 的实例:

s1 = Singleton()
s2 = Singleton()

assert s1 is s2  # True

以上面的代码为例,因为 Singleton 的实例只能有一个,所以 s1 和 s2 其实是同一个实例对象,因此 s1 is s2 的结果为 True。  

实例2:

Python 还提供了一种更简洁的方式来实现单例模式,那就是使用 call 方法。具体而言,我们只需要将要实现单例模式的类定义为一个 callable 对象,并在类中定义 call 方法,这个类的实例就可以像函数一样被调用了  

class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __call__(cls, *args, **kwargs):
        return cls._instance

在这个示例中,我们定义了一个名为 Singleton 的类,其中包含了一个类变量 _instance 和一个 __call__ 方法。在 __call__ 方法中,我们直接返回 _instance 变量,这样当我们像调用函数一样调用 Singleton 的实例时,实际上返回的是同一个对象。

使用时,我们可以像下面这样来创建 Singleton 的实例:

s1 = Singleton()
s2 = Singleton()

assert s1 is s2  # True

以上面的代码为例,因为 Singleton 的实例只能有一个,所以 s1 和 s2 其实是同一个实例对象,因此 s1 is s2 的结果为 True  

实例3:

使用装饰器:装饰器可以用于装饰一个类,使其在实例化时返回同一对象。具体实现方式与以上的元类类似。

def singleton(cls):
    _instances = {}

    def get_instance(*args, **kwargs):
        if cls not in _instances:
            _instances[cls] = cls(*args, **kwargs)
        return _instances[cls]

    return get_instance

@singleton
class MySingleton:
    pass

s1 = MySingleton()
s2 = MySingleton()

print(s1 is s2)  # 输出:True

实例4:

使用模块:Python 中的模块是天然的单例,因为在导入模块时只会执行一次初始化代码,后续的导入操作都是返回同一份已经初始化过的对象。因此可以将需要实现单例的类定义在一个模块中,直接导入该模块即可获得该类的唯一实例。

# singleton.py
class MySingleton:
    pass

my_singleton = MySingleton()  # 创建唯一实例

# main.py
from singleton import my_singleton

print(my_singleton)  # 输出:<singleton.MySingleton object at 0x7f5d5e9780f0>

以上4种实现方式都可以达到单例模式的效果,其中使用模块的方式代码量最少,但有些情况下可能不太灵活;使用元类和装饰器的方式代码量较多,但可以更加灵活地控制单例的创建过程。  

  

 

posted @ 2023-04-16 23:44  橘子偏爱橙子  阅读(19)  评论(0编辑  收藏  举报