Python小白学习教程从入门到入坑------第二十六课 单例模式(语法进阶)

在这个节课的开始,我们先回顾一下面向对象课程中学的构造函数__init__()

目录

一、__init__() 和 __new__()

1.1 __init__()

1.2 __new__()

二、单例模式

2.1 特点

2.2 通过@classmethod实现单例模式

2.3 通过装饰器实现单例模式

2.3 通过重写__new__() 实现单例模式

2.4 通过导入模块实现单例模式

三、单例模式的应用场景




一、__init__() 和 __new__()

1.1 __init__()

作用:初始化对象

eg:

class Test(object):def __init__(self):print("这是__init__()")
te = Test()
# 输出结果:这是__init__()

1.2 __new__()

__new__(): object 基类提供的内置的静态方法

作用:

1、在内存中为对象分配空间

2、返回对象的引用

eg:

class Test(object):def __init__(self):print("这是__init__()")def __new__(cls, *args, **kwargs):     # cls代表类本身print("我是__new__()")
te = Test()
# 输出结果:我是__new__()

我们会发现,这里面的__init__方法没有输出 ,这是为什么呢?

其实是因为我们在__new__方法中将__new__方法改写了,改变了python中默认__new__的功能,改成了print("我是__new__()"),所以__init__方法没有输出

我们接下来试着打印一下te和cls

eg:没有__new__() 方法时

class Test(object):def __init__(self):print("这是__init__()")
te = Test()
print(te)
# 输出结果:
# 这是__init__()
# <__main__.Test object at 0x000001BF8ABFE148>

 加入__new__() 方法时:

class Test(object):def __init__(self):print("这是__init__()")def __new__(cls, *args, **kwargs):print("我是__new__()")print(cls)
te = Test()
print(te)
# 输出结果:
# 我是__new__()
# <class '__main__.Test'>
# None

发现此时te输出为None,就是因为__new__的功能被覆盖改写了

那么我们如果想修改原有的代码,却还想继承原有代码的功能,那么我们该怎么做呢?

我们需要用到之前学习的扩展

eg:

class Test(object):def __init__(self):print("这是__init__()")def __new__(cls, *args, **kwargs):print("我是__new__()")print(cls)# 对父类方法进行扩展   推荐使用super().方法名()res = super().__new__(cls)# 方法重写,res里面保存的是实例对象的引用,__new__()是静态方法,形参里面有cls,实参就必须传clsreturn res# 注意:重写__new__() 一定要return super().__new__(cls),否则python解释器得不到分配空间的对象引用,就不会调用__init__()
te = Test()
print("te:",te)
# 输出结果:
# 我是__new__()
# <class '__main__.Test'>
# 这是__init__()
# te: <__main__.Test object at 0x0000021EBEBEE548>

执行步骤:

一个对象的实例化过程:首先执行__new__(),如果没有写__new__(),默认调用object 里面的__new__(),返回一个实例对象,然后再去调用__init__(),对对象进行初始化

eg:

class Person(object):def __new__(cls, *args, **kwargs):print("这是new方法")print("返回值:",super().__new__(cls))return super().__new__(cls)def __init__(self,name):self.name = name   # 实例属性print("名字是:",self.name)
pe = Person('junjun')
print(pe)
pe2 = Person('susu')
print(pe2)
# 输出结果:
# 这是new方法
# 返回值: <__main__.Person object at 0x000002564FA1E5C8>
# 名字是: junjun
# <__main__.Person object at 0x000002564FA1E5C8>
# 这是new方法
# 返回值: <__main__.Person object at 0x000002564FA1E608>
# 名字是: susu
# <__main__.Person object at 0x000002564FA1E608>

总结:__init__() 和 __new__()

1、__new__() 是创建对象,__init__() 是初始化对象

2、__new__() 是返回对象引用,__init__() 定义实例属性

3、__new__() 是类级别的方法,__init__() 是实例级别的方法

二、单例模式

2.1 特点

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例

当你希望在整个系统中,某个类只能出现一个实例时,单例模式就能排上用场(可以简单理解成一个特殊的类,这个类只存在一个对象)

优点:可以节省内存空间,减少了不必要的资源浪费

弊端:多线程访问的时候容易引发线程安全问题

在 Python 中,有多种方式实现单例模式,以下是一些常见的方法:

1、通过@classmethod

2、通过装饰器实现

3、通过重写__new__() 实现(重点)

4、通过导入模块实现

注意:单例模式简单来说就是每一次实例化所创建的对象都是同一个,即内存地址相同

2.2 通过@classmethod实现单例模式

这种方法利用类方法 @classmethod 和一个类变量来追踪单例实例

eg:

class Singleton:  _instance = None  @classmethod  def get_instance(cls, *args, **kwargs):  if cls._instance is None:  cls._instance = cls(*args, **kwargs)  return cls._instance  def __init__(self, value=None):  if not hasattr(self, 'initialized'):  # 防止重复初始化  self.value = value  self.initialized = True  # 测试  
if __name__ == "__main__":  s1 = Singleton(10)  s2 = Singleton.get_instance(20)  # 这里传递的 20 将被忽略,因为实例已经存在  print(s1.value)  # 输出: 10  print(s2.value)  # 输出: 10,而不是 20  print(s1 is s2)  # 输出: True

注意:上面的实现中,__init__ 方法被修改以防止重复初始化。这是因为在第一次创建实例后,后续通过 get_instance 获取实例时不会再次调用 __init__

2.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 Singleton:  def __init__(self, value):  self.value = value  # 测试  
if __name__ == "__main__":  s1 = Singleton(10)  s2 = Singleton(20)  # 这里传递的 20 将被忽略,因为实例已经存在(通过装饰器控制)  print(s1.value)  # 输出: 10  print(s2.value)  # 输出: 10  print(s1 is s2)  # 输出: True

2.3 通过重写__new__() 实现单例模式

这是最常见和推荐的方法之一,因为它在对象创建的最早阶段就进行控制

设计流程:

1、定义一个类属性,初始值为None,用来记录单例对象的引用

2、重写__new__() 方法

3、进行判断,如果类属性是None,把__new__() 返回的对象引用保存进去

4、返回类属性中记录的对象引用

class Singleton:  _instance = None   # 类属性def __new__(cls, *args, **kwargs):  if cls._instance is None:  # 判断类属性是否为空cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)  return cls._instance  def __init__(self, value=None):  if not hasattr(self, 'initialized'):  # 防止重复初始化(同样的问题)  self.value = value  self.initialized = True  # 测试  
if __name__ == "__main__":  s1 = Singleton(10)  s2 = Singleton(20)  # 这里传递的 20 将被忽略  print(s1.value)  # 输出: 10  print(s2.value)  # 输出: 10  print(s1 is s2)  # 输出: True

2.4 通过导入模块实现单例模式

Python 模块在第一次导入时会被初始化,并且只会被初始化一次。因此,可以利用这一特性实现单例。

首先,创建一个模块 singleton_module.py:

# singleton_module.py  
class Singleton:  def __init__(self, value):  self.value = value  singleton_instance = Singleton(10)  # 创建单例实例

然后,在其他文件中使用:

# main.py  
import singleton_module  # 测试  
if __name__ == "__main__":  s1 = singleton_module.singleton_instance  # 尝试重新赋值不会改变单例实例  # singleton_module.singleton_instance = Singleton(20)  # 这行不会影响已经存在的实例  # 但可以通过实例的属性进行修改(如果允许的话)  # s1.value = 20  # 这会改变实例的 value 属性  s2 = singleton_module.singleton_instance  print(s1.value)  # 输出: 10  print(s2 is s1)  # 输出: True

注意:在模块级单例中,如果直接修改 singleton_module.singleton_instance 指向另一个对象,那么会破坏单例模式。但是,如果通过实例的属性进行修改(如 s1.value = 20),则不会破坏单例模式,只是改变了实例的状态

三、单例模式的应用场景

1.回收站对象

2.音乐播放器,一个音乐播放软件负责音乐播放的对象只有一个

3.开发游戏软件场景管理器

4.数据库配置、数据库连接池的设计

今天的分享就到这里了,希望本文能够对大家有些许的帮助~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/59868.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

x-cmd pkg | onefetch - 轻松获取 Git 仓库统计信息,打造个性化输出!

目录 简介首次用户功能特点常见用法类似或相关的工具进一步阅读 简介 onefetch 是由 Ossama Hjaji 用 Rust 编写的命令行 Git 信息工具&#xff0c;可将本地 Git 存储库的项目信息和代码统计信息直接显示到您的终端。该工具完全离线 - 不需要网络访问。 首次用户 本文的 dem…

基于IM场景下的Wasm初探:提升Web应用性能|得物技术

一、何为Wasm &#xff1f; Wasm&#xff0c;全称 WebAssembly&#xff0c;官网描述是一种用于基于堆栈的虚拟机的二进制指令格式。Wasm被设计为一个可移植的目标&#xff0c;用于编译C/C/Rust等高级语言&#xff0c;支持在Web上部署客户端和服务器应用程序。 Wasm 的开发者参…

现场工程师日记-MSYS2迅速部署PostgreSQL主从备份数据库

文章目录 一、概要二、整体架构流程1. 安装 MSYS2 环境2. 安装postgresql 三、技术名词解释1.MSYS22.postgresql 四、技术细节1. 创建主数据库2.添加从数据库复制权限3. 按需修改参数&#xff08;1&#xff09;WAL保留空间&#xff08;2&#xff09;监听地址 4. 启动主服务器5.…

《应用数学和力学》

作者须知 1.《应用数学和力学》(Applied Mathematics and Mechanics)于1980年由我国著名科学家钱伟长先生在重庆交通大学创办&#xff0c;创刊时为季刊&#xff0c;翌年增为双月刊&#xff0c;1985年起扩大为月刊。期刊主要刊登力学、力学中的数学方法和与现代力学紧密相关的应…

【CSS】标准怪异盒模型

概念 CSS 盒模型本质上是一个盒子&#xff0c;盒子包裹着HTML 元素&#xff0c;盒子由四个属性组成&#xff0c;从内到外分别是&#xff1a;content 内容、padding 内填充、border 边框、外边距 margin 盒模型的分类 W3C 盒子模型(标准盒模型) IE 盒子模型(怪异盒模型) 两种…

什么是PHP,有什么特点

PHP 简介 PHP&#xff08;Hypertext Preprocessor&#xff09;是一种广泛使用的开源脚本语言&#xff0c;特别适合 Web 开发。PHP 代码可以直接嵌入到 HTML 中&#xff0c;也可以作为独立的脚本文件运行。PHP 的设计目标是使开发者能够快速编写动态和交互式的 Web 应用程序。P…

[前端项目Overview]表单构建器vue-form-generator

GitHub - vue-generators/vue-form-generator: :clipboard: A schema-based form generator component for Vue.js vue-generator-form 是一个基于 Vue.js 的表单生成器项目&#xff0c;用于动态地生成表单。它主要用于处理复杂的动态表单需求&#xff0c;比如根据 JSON 配置自…

Android中桌面小部件framework层使用到的设计模式

在Android中&#xff0c;桌面小部件&#xff08;App Widget&#xff09;的Framework层采用了多种设计模式&#xff0c;以实现模块化、可维护性和高效的交互。 以下是Android桌面小部件Framework层中常用的设计模式及其具体应用&#xff1a; 1. 观察者模式&#xff08;Observe…

半波正弦信号的FFT变换

目录 Hello&#xff0c; 大家好&#xff0c;这一期我们谈谈半波正弦信号的FFT变化长什么样子。本文硬件使用GFARM02硬件模块[1]&#xff0c;文章最后有其淘宝链接。核心器件为STM32F103RCT6&#xff0c;为Cortex-M3核&#xff0c;采用的CMSIS版本为CMSIS_5-5.6.0。 如图1所示&…

基于SpringBoot和Vue的公司文档管理系统设计与开发(源码+定制+开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

nvm 切换 Node.js 版本

nvm 切换 Node.js 版本 0. nvm 安装1. 查看装了哪些 Node.js 版本2. 安装 Node.js 版本安装最新稳定版本.安装个18 3. 切换 Node.js 版本4. 设置默认 Node.js 版本5. 卸载 Node.js 版本6.与项目的配合使用参考资料 0. nvm 安装 安装教程就不写了&#xff0c;直接看别人的。 脚…

深度学习:解密图像、音频和视频数据的“理解”之道20241105

&#x1f50d; 深度学习&#xff1a;解密图像、音频和视频数据的“理解”之道 深度学习已然成为人工智能领域的中流砥柱&#xff0c;它如何处理不同类型的数据&#xff08;如图像、音频、视频&#xff09;&#xff1f;如何将这些数据转换成计算机能理解和学习的“语言”&#…

Linux服务器或Linux计算机设置不记录历史命令

1.设置环境变量 打开命令终端&#xff0c;编辑.bashrc文件中&#xff0c;修改HISTSIZE和HISTFILESIZE都为0 sudo nano ~/.bashrcfor setting history length see HISTSIZE and HISTFILESIZE in bash(1) HISTSIZE0 HISTFILESIZE0 2.生效 source ~/.bashrc 3.验证 cat ./b…

数据库内核研发学习之路(六)使用共享内存

postgres共享内存 目录 1 一、创建内置函数2 二、创建共享内存的声明shmstring.h文件3 三、创建两个函数的实现4 四、在ipci文件中加载共享内存 1 一、创建内置函数 共享内存的使用&#xff0c;这里是开两个psql连接&#xff0c;一个连接调用内置函数set_string设置一个字符…

【问题解决】Tomcat由低于8版本升级到高版本使用Tomcat自带连接池报错无法找到表空间的问题

问题复现 项目上历史项目为解决漏洞扫描从Tomcat 6.0升级到了9.0版本&#xff0c;服务启动的日志显示如下警告&#xff0c;数据源是通过JNDI方式在server.xml中配置的&#xff0c;控制台上狂刷无法找到表空间的错误&#xff08;没截图&#xff09; 报错&#xff1a; 06-Nov-…

接口测试用例设计的关键步骤与技巧解析!

简介 接口测试在需求分析完成之后&#xff0c;即可设计对应的接口测试用例&#xff0c;然后根据用例进行接口测试。接口测试用例的设计也需要用到黑盒测试用例设计方法&#xff0c;和测试流程与理论章节的功能测试用例设计的方法类似&#xff0c;设计过程中还需要增加与接口特…

【数据集】【YOLO】【目标检测】树木倒塌识别数据集 9957 张,YOLO道路树木断裂识别算法实战训练教程!

一、数据集介绍 【数据集】树木倒塌识别数据集 9957 张&#xff0c;目标检测&#xff0c;包含YOLO/VOC格式标注。 数据集中包含1种分类&#xff1a;{0: fallen_tree}&#xff0c;代表倒塌或者断裂的树木。 数据集来自国内外图片网站和视频截图&#xff1b; 可用于无人机树木…

[极客大挑战 2019]PHP 1

[极客大挑战 2019]PHP 1 审题 猜测备份在www.zip中&#xff0c;输入下载文件。 知识点 反序列化 解题 查看代码 看到index.php中包含了class.php,直接看class.php中的代码 查看条件 当usernameadmin&#xff0c;password100时输出flag 构造反序列化 输入select中&#…

初识机器学习

目录 什么是机器学习&#xff1f; 机器学习的基本过程&#xff1a; 监督学习 监督学习的工作原理 监督学习的应用 监督学习的优缺点 总结 非监督学习 非监督学习的工作原理 非监督学习的应用 非监督学习的优缺点 总结 什么是机器学习&#xff1f; 机器学习&#xf…

网络层5——IPV6

目录 一、IPv6 vs IPv4 1、对IPv6主要变化 2、IPv4 vs IPv6 二、IPv6基本首部 1、版本——4位 2、通信量类——8位 3、流标号——20位 4、有效载荷长度——16位 5、下一个首部——8位 6、跳数限制——8位 7、源 、 目的地址——128位 8、扩展首部 三、IPv6地址 1…