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 自动传入实例
访问范围 类属性、类方法 实例属性、实例方法、类属性
相关推荐
果汁华19 分钟前
Browserbase Skills:让 Claude Agent 真正“看见“网页世界
人工智能·python
ZhengEnCi19 分钟前
04-缩放点积注意力代码实现 💻
人工智能·python
DeepReinforce1 小时前
三、AI量化投资:使用akshare获取A股主板20260430所有的涨停股票
python·量化·akshare·龙头战法
段一凡-华北理工大学1 小时前
【高炉炼铁领域炉温监测、预警、调控智能体设计与应用】~系列文章08:多模态数据融合:让数据更聪明
人工智能·python·高炉炼铁·ai赋能·工业智能体·高炉炉温
万粉变现经纪人1 小时前
如何解决 pip install llama-cpp-python 报错 未安装 CMake/Ninja 或 CPU 不支持 AVX 问题
开发语言·python·开源·aigc·pip·ai写作·llama
清风明月一壶酒2 小时前
OpenClaw自动处理Word文档全流程
开发语言·c#·word
其实防守也摸鱼2 小时前
CTF密码学综合教学指南--第五章
开发语言·网络·笔记·python·安全·网络安全·密码学
callJJ3 小时前
Spring Data Redis 两种编程模型详解:同步 vs 响应式
java·spring boot·redis·python·spring
小郑加油3 小时前
python学习Day12:pandas安装与实际运用
开发语言·python·学习
AC赳赳老秦3 小时前
投标合规提效:用 OpenClaw 实现标书 / 合同自动审核、关键词校验、格式优化,降低废标风险
开发语言·前端·python·eclipse·emacs·deepseek·openclaw