Python - 面向对象编程 - __new()__ 和单例模式
单例模式
这是一种设计模式
- 设计模式是前任工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对某一特定问题的成熟的解决方案
- 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性
单例设计模式
- 目的:让某一个类创建的实例对象,在整个应用程序中只有唯一的一个实例对象而且该对象易于外界访问,从而方便对实例个数的控制并节约系统资源
- 每一次执行 类名() 返回的对象,内存地址是相同的
单例设计模式的应用场景
- 音乐播放器对象
- 回收站对象
- 打印机对象
- .....
为什么要单例模式?
- 提问:如何保证一个类只有一个实例并且这个实例易于被访问呢?
- 不使用单例模式:定义一个全局变量可以确保对象随时都可以被访问,但不能防止实例化多个对象
- 单例模式的出现:类自己负责只能创建一个实例对象,可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法
__new__ 方法
使用 类名() 创建对象时,Python 的解释器首先会调用 __new__ 方法为对象分配内存空间
class PoloBlog:
def __new__(cls, *args, **kwargs):
print("分配内存地址啦") def __init__(self):
print("初始化对象...") blog = PoloBlog()
print(blog) # 输出结果
分配内存地址啦
None
哎,为什么打印对象是 None,而且没有调用到 __init__ 方法呢??下面讲解!
内置的静态方法

__new__ 是一个由 object 基类提供的内置的静态方法
__new__ 主要作用
- 在内存中为实例对象分配空间
- 返回对象的引用给 Python 解释器
Python 的解释器获得对象的引用后,将对象的引用作为第一个参数,传递给 __init__ 方法

重写 __new__ 方法
- 重写的代码是固定的
- 重写 __new__ 方法一定要在最后 return super().__new__(cls)
- 如果不 return(像上面代码栗子一样),Python 的解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法(__init__)
- 重点:__new__ 是一个静态方法,在调用时需要主动传递 cls 参数
class PoloBlog:
def __new__(cls, *args, **kwargs):
# 1、自动调用 __new__
print("分配内存地址啦")
# 2、为对象分配空间得到的引用赋值给 instance
instance = super().__new__(cls)
print(id(instance))
# 3、返回对象引用给 Python 解释器
return instance def __init__(self):
print("初始化对象...")
print(id(self)) blog = PoloBlog() # 输出结果
分配内存地址啦
4363809888
初始化对象...
4363809888
可以看到打印的两个内存地址是同一个哦:证明 __new__ 分配的对象引用的确传给了 __init__ 方法的 self 参数
__new__ 实现单例模式
class PoloBlog:
def __new__(cls, *args, **kwargs):
print("分配内存地址啦")
instance = super().__new__(cls)
return instance def __init__(self):
print("初始化对象...") blog = PoloBlog()
blog1 = PoloBlog() print(id(blog))
print(id(blog1)) # 输出结果
4449363040
4449361984
很明显,两个对象各有自己的内存地址;单纯的重写 __new__ 方法并不能实现单例模式
__new__ 实现单例模式的逻辑
单例:在整个应用程序中只有唯一的一个实例对象
- 定义一个类属性,来保存单例对象的引用
- 重写 __new__ 方法
- 如果类属性 is None,则调用父类方法分配内存空间,并赋值给类属性
- 如果类属性已有对象引用,则直接返回
单例模式的代码实现
# 单例模式
class PoloBlog:
instance = None def __new__(cls, *args, **kwargs):
# 1、判断类属性是否为 None
if cls.instance is None:
# 2、为空,调用父类方法,给对象分配内存空间,并赋值给类属性
cls.instance = super().__new__(cls) # 3、如果不为空,则直接返回类属性保存的对象引用
return cls.instance def __init__(self):
pass blog = PoloBlog()
blog1 = PoloBlog()
blog2 = PoloBlog()
print(id(blog), id(blog1), id(blog2)) # 输出结果
4336982096 4336982096 4336982096
可以看到创建的三个实例对象其实都是同一个,这就是单例模式!
初始化工作仅执行一次
在每次使用类名()创建对象时,Python 的解释器都会自动调用两个方法
- __new__ 分配空间
- __init__ 对象初始化
上面所说的单例模式,是针对 __new__ 方法进行重写的,创建多个实例对象都会得到同一个实例对象
但是:初始化方法还是会被多次调用
class PoloBlog:
instance = None def __new__(cls, *args, **kwargs):
if cls.instance is None: cls.instance = super().__new__(cls) return cls.instance def __init__(self):
print("yep") blog = PoloBlog()
blog1 = PoloBlog()
blog2 = PoloBlog() # 输出结果
yep
yep
yep
假设想让初始化动作只执行一次呢?
其也很简单,和单例模式的解决思路差不多
- 定义一个类属性标记是否执行过初始化动作,初始值为 False
- 在 __init__ 方法中,判断类属性,如果 False,则执行初始化动作,然后设置为 True
- 如果 True 则直接跳过不执行
# 单例模式
class PoloBlog:
instance = None
init_flag = None def __new__(cls, *args, **kwargs):
if cls.instance is None: cls.instance = super().__new__(cls) return cls.instance def __init__(self):
# 1、判断是否为 True,因为是实例方法,所以调用类属性要通过类对象
if PoloBlog.init_flag:
# 2、如果 True,直接跳过不执行后续初始化动作
return
# 3、如果 False,则执行
print("初始化动作")
# 4、修改 init_flag
PoloBlog.init_flag = True blog = PoloBlog()
blog1 = PoloBlog()
blog2 = PoloBlog() # 输出结果
初始化动作
Python - 面向对象编程 - __new()__ 和单例模式 的更多相关文章
- python 面向对象编程学习
1. 问题:将所有代码放入一个py文件:无法维护 方案:如果将代码才分放到多个py文件,好处: 1. 同一个名字的变量互相不影响 2.易于维护 3.引用模块: import module 2.包:解决 ...
- python 面向对象编程(一)
一.如何定义一个类 在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法. 类是对现实世界中一些事物的封装,定义一个类可以采用下面的方式来定义: class c ...
- Python 面向对象编程——访问限制
<无访问限制的对象> 在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑.但是,从前面Student类的定义来看(见:Py ...
- Python 面向对象编程基础
Python 面向对象编程基础 虽然Pthon是解释性语言,但是Pthon可以进行面向对象开发,小到 脚本程序,大到3D游戏,Python都可以做到. 一类: 语法: class 类名: 类属性,方法 ...
- python面向对象编程学习
python面向对象编程 基本概念理解 面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作 ...
- Python面向对象编程指南
Python面向对象编程指南(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1SbD4gum4yGcUruH9icTPCQ 提取码:fzk5 复制这段内容后打开百度网 ...
- python面向对象编程进阶
python面向对象编程进阶 一.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1 ...
- Python面向对象编程(下)
本文主要通过几个实例介绍Python面向对象编程中的封装.继承.多态三大特性. 封装性 我们还是继续来看下上文中的例子,使用Student类创建一个对象,并修改对象的属性.代码如下: #-*- cod ...
- Python 面向对象编程 继承 和多态
Python 面向对象编程 继承 和多态 一:多继承性 对于java我们熟悉的是一个类只能继承一个父类:但是对于C++ 一个子类可以有多个父亲,同样对于 Python一个类也可以有多个父亲 格式: c ...
随机推荐
- 一键设置WPS_Office_2019专业版的定时自动备份的批处理文件
一键设置WPS_Office_2019专业版的定时自动备份的批处理文件 rem ================================================ rem 一键设置WPS ...
- 自学linux——6.安全外壳协议(ssh服务)
ssh服务 ssh(secure shell)安全外壳协议:远程连接协议,远程文件传输协议 1.协议使用端口号默认:22 若要修改,则修改ssh服务的配置文件/etc/ssh/ssh_config a ...
- CF559B Equivalent Strings TJ
前言 题目传送门 正解:模拟,递归. 考试的 T4,还是想复杂了 qwq. 这题不要用 STL,容易 \(\texttt{TLE}\)!! 题意简述 翻译够简了. 对了给一下样例解释的翻译: 第一个样 ...
- [GXYCTF2019]Ping Ping Ping(ping命令执行绕过Waf)
记一道ping注入的题.过滤了很多字符. 分析 简单的测了一下,很容易就拿到了flag.php和index.php. 但是存在waf无法直接查看.直接?ip=127.0.0.1|cat flag.ph ...
- Salesforce Integration 概览(六) UI Update Based on Data Changes(UI自动更新基于数据变更)
Salesforce用户界面必须由于Salesforce数据的更改而自动更新.这个场景其实在我所经历的项目中用到的不是特别多,因为客户可能直接点击刷新按钮就直接看到了最新的数据,而不是那种一直不刷新然 ...
- remote: Support for password authentication was removed
周末提交代码,把代码push到github上,控制台报了下面的错误: remote: Support for password authentication was removed on August ...
- vue源码解析之响应式原理
关于defineReactive等使用细节需要自行了解 一些关键知识点 $mount时 会 new Watcher 把组件的 updateComponent 方法传给watcher 作为getter ...
- 腾讯云TDSQL MySQL版 - 开发指南 二级分区
TDSQL MySQL版 目前支持 Range 和 List 两种格式的二级分区,具体建表语法和 MySQL 分区语法类似. 二级分区语法 一级 Hash,二级 List 分区示例如下: MySQL ...
- Win10下安装SVN出现2503/2502解决方法
出现错误的原因是权限不够 在win10的开始按钮上,右键点击,选择"命令提示符(管理员)(A)",弹出管理员身份运行模式的命令行的窗口,输入如下的命令: msiexec /pack ...
- C#基础知识---?为何物
一. 可空类型修饰符(?)引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; 是正确的,int i=null; 编译器就会报错.可空类型的出现, ...
