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 ...
随机推荐
- Distance Queries 距离咨询 (LCA倍增模板)
农夫约翰有N(2<=N<=40000)个农场,标号1到N.M(2<=M<=40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地 ...
- Java面向对象06——类与对象小结
小结 /* 1. 类与对象 类是一个模板:抽象,对象是一个具体的实例 2. 方法 定义.调用 3. 对应的引用 引用类型: 基本类型(8) 对象是通过引用来操作的:栈-- ...
- 接口管理效率神器Apifox
前言 你是一个测试,你们团队目前开发模式是前后端分离. 某一天,版本V1.0接口评审完,发布在了swagger上,前后端各自进行开发.此时你根据接口文档将新接口迁移到JMeter上,然后开始编写接口测 ...
- MapReduce框架原理-MapTask和ReduceTask工作机制
MapTask工作机制 并行度决定机制 1)问题引出 maptask的并行度决定map阶段的任务处理并发度,进而影响到整个job的处理速度.那么,mapTask并行任务是否越多越好呢? 2)MapTa ...
- 『Java』StringBuilder类使用方法
String类存在的问题 String类的底层是一个被final修饰的byte[],不能改变. 为了解决以上问题,可以使用java.lang.StringBuilder类. StringBuilder ...
- Redis-02-主从复制和哨兵模式
安全认证 开启认证 redis默认开启了保护模式,只允许本地回环地址登录并访问数据库 修改redis的配置文件,并重启redis的服务 vim /opt/redis_cluster/redis_637 ...
- 附件携马之CS免杀shellcode过国内主流杀软
0x01 写在前面 其实去年已经写过类似的文章,但是久没用了,难免有些生疏.所谓温故而知新,因此再详细的记录一下,一方面可以给各位看官做个分享,另一方面等到用时也不至于出现临阵磨枪的尴尬场面. 0x0 ...
- Beescms V4.0_R_20160525代码审计笔记
写在前面 什么是报错注入?正常用户访问服务器发送id信息返回正确的id数据.报错注入是想办法构造语句,让错误信息中可以显示数据库的内容:如果能让错误信息中返回数据库中的内容,即实现SQL注入. 复现过 ...
- Proxifier/ProxyChains+reGeorg组合进行内网代理
在内网渗透过程中,我们经常使用sockes代理工具,本文主要介绍攻击机为windows和linux情况下得使用方式. Win:proxifier+reGeorg 组合 Linux:proxychain ...
- VMware 启动虚拟机黑屏(Ubuntu)
之前启动都很正常,不知道为啥,最近启动,老出现这种黑屏得情况: 解决方法: 在搜索栏里搜索cmd 巴拉了一下谷歌,发现了问题: 虚拟机和主机之间的通信,基本上是以 socket 的方式进行通信的(这里 ...
