python:单例模式

首先说一下,查询了这么多单例模式的讲解,还是bilibili的这个视频讲解最清楚、简洁、实用且到位bilibili单例模式

https://www.bilibili.com/video/BV1cK4y1n7DC/?spm_id_from=333.1391.0.0&p=4&vd_source=58cc5704c1268f656a4d51980dac6aa7

以上是单例模式的应用方法与思路

复制代码
class MusicPlayer(object):

    def __new__(cls, *args, **kwargs):
        # 1.创建对象时,new方法会被自动调用
        print("创建对象,分配空间")
        # 2.为对象分配空间(调用父类的new方法)
        instance = super().__new__(cls)
        # 3.返回对象的引用
        return instance

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

#创建播放器对象
player = MusicPlayer()
print(player)

以上Python 代码展示了单例模式__new__方法的基础使用,__new__是 Python 中用于创建实例的静态方法(特殊方法),负责为对象分配内存空间,而__init__是实例初始化方法,负责对已创建的实例进行属性初始化。下面为你详细解析这段代码的执行逻辑、输出结果,以及进一步的扩展(比如实现单例模式)。

代码执行流程与输出解析

  1. 调用MusicPlayer()创建对象时,首先触发__new__方法

    • 执行print("创建对象,分配空间"),打印该字符串。
    • 调用父类(object)的__new__方法:super().__new__(cls),为MusicPlayer实例分配内存空间,返回实例的引用(instance)。
    • __new__方法返回实例引用,这个引用会作为self参数传递给__init__方法。
  2. 接着触发__init__方法

    • 执行print("播放器初始化"),打印该字符串。
  3. 最后打印player对象

    • 输出对象的内存地址(格式类似<__main__.MusicPlayer object at 0x0000021Fxxxxxx>)。

最终输出结果

复制代码
创建对象,分配空间
播放器初始化
<__main__.MusicPlayer object at 0x0000021Fxxxxxx>  # 地址会随环境变化

关键知识点:__new____init__的区别

特性 __new__ __init__
作用 创建实例,分配内存空间 初始化实例,为实例设置属性
调用时机 实例创建时最先调用 __new__返回实例后调用
参数 第一个参数是类(cls 第一个参数是实例(self
返回值 必须返回实例引用(否则__init__不执行) 无返回值(None

扩展:利用__new__实现单例模式

单例模式的核心是一个类只能创建一个实例 。通过重写__new__方法,我们可以控制实例的创建逻辑,确保始终返回同一个实例。修改后的代码如下:

复制代码
class MusicPlayer(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("播放器初始化")

# 创建多个对象,验证是否为同一个实例
player1 = MusicPlayer()
player2 = MusicPlayer()
print(f"player1与player2是否为同一对象: {player1 is player2}")

输出结果

复制代码
播放器初始化
播放器初始化
player1与player2是否为同一对象: True

说明

  • player1player2是同一个实例(is判断为True),但__init__被调用了两次(实例化player1时调用了第一次初始化init,实例化player2时第二次调用了init)。如果需要让__init__只执行一次,可以在__new__中增加额外的判断标记。

进阶:单例模式且__init__只执行一次

复制代码
class MusicPlayer(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 MusicPlayer.init_flag:
            print("播放器初始化")
            MusicPlayer.init_flag = True  # 初始化后将标记设为True

player1 = MusicPlayer()
player2 = MusicPlayer()
print(f"player1与player2是否为同一对象: {player1 is player2}")

输出结果

复制代码
播放器初始化
player1与player2是否为同一对象: True

此时,无论创建多少个MusicPlayer实例,都只会执行一次初始化逻辑,且所有实例指向同一个内存地址。(第一次实例化的时候,将标志init_flag=true置为真了,第二次实例化的时候,if not init_flag就是假,程序不再继续向下执行,所以只执行了第一次的初始化,后续的就不再执行了)

clsself的区别

特性 cls self
代表对象 类本身(类对象) 类的实例(实例对象)
适用方法 类方法、__new__方法 实例方法
传递方式 Python 自动传入类本身 Python 自动传入实例
访问范围 类属性、类方法 实例属性、实例方法、类属性
相关推荐
摸鱼仙人~5 小时前
一文详解text2vec库
开发语言·python
jghhh015 小时前
基于C#的串口电子秤测试程序
开发语言·c#
natide5 小时前
词汇/表达差异-6-n-gram分布距离
人工智能·python·算法
Yolo566Q5 小时前
环境多介质逸度模型实践技术与典型案例【代码】应用
python
饕餮争锋5 小时前
pip install 报错This environment is externally managed
开发语言·python·pip
superman超哥5 小时前
仓颉语言导入语句使用深度解析
c语言·开发语言·c++·python·仓颉
Amelia1111115 小时前
day33
python
数据知道5 小时前
一文掌握向量数据库Chroma的详细使用
数据库·python·向量数据库
阿闽ooo5 小时前
单例模式深度解析:从饿汉到懒汉的实战演进
开发语言·c++·笔记·设计模式