Python中使用__new__实现单例模式并解析


Posted in Python onJune 25, 2019

单例模式是一个经典设计模式,简要的说,一个类的单例模式就是它只能被实例化一次,实例变量在第一次实例化时就已经固定。

 在Python中常见的单例模式有None,这就是一个很典型的设计,通常使用 if xxx is None或者if xxx is not None来比较运算。

Python实现单例模式

代码如下:

class MyClass:
  _instance = None 
  _first_init = False 
  def __new__(cls, *args, **kwargs):
    if not cls._instance:
      cls._instance = super().__new__(cls)
    return cls._instance
  def __init__(self, var1, var2):
    cls = type(self)
    if not cls._first_init:
      self.var1 = var1
      self.var2 = var2
      cls._first_init = True

如上所示,我创建了一个MyClass的类,定义了两个类变量,第一个是_instance,它负责保存该类创建的实例。第二个是_first_init,它是一个布尔值,保存是否为第一次实例化该类。

在__new__方法中(构造函数),判断是否存在_instance这个类变量,如果之前已经实例化了,直接返回。如果是第一次实例化,就会为_instance类变量绑定实例,使用super().__new__(cls)创建实例,即调用父类object.__new__(MyClass)创建实例。

在__init__方法中(初始化函数),我们通过cls=type(self)获取MyClass类,判断是否第一次实例化。如果是第一次实例化,就绑定实例变量。否则什么都不做.

运行效果

我们创建两个实例,来对比

>>> instance1 = MyClass(1, 2)
>>> instance2 = MyClass(7, 5)
>>> id(instance1) == id(instance2)
True

>>> instance2.var1
1

可以看到,这两个实例的内存地址都相同,而且第一次实例化后变量已经固定了,全局不会再改变。

这就是单例模式的实现。

ps:下面看下Python中类方法、__new__方法和__init__方法解析

在编程语言中创建一个类,有构造方法这样的一个术语。而在Python中,通常大家都认为__init__是构造方法,其实并不完全等同。在构建类中,有一个特殊的方法__new__,这个才能等同为构造方法。

__new__是一个类方法,我们在定义一个类方法时需要在函数前打上@classmethod装饰器,而__new__不需要,因为它经过特殊处理。为了理解__new__方法,我们先来看看类方法是什么。

类方法

class MyClass:

  @classmethod
  def test(cls):
    print(cls.__name__)
    
MyClass.test()
#输出 MyClass

在MyClass类中,test方法就是类方法,它传入第一个参数为cls,其实就是MyClass类,打印cls.__name__可以看到结果。类方法可以直接 类名.方法名()调用。通常类方法是备选构造方法。

类方法的应用

>>> from datetime import datetime
>>> datetime.fromtimestamp(324234)
datetime.datetime(1970, 1, 5, 2, 3, 54)

如上所示,内置的datetime包中的fromtimestamp就是类方法,可以从多种方式构造出datetime对象。

__new__方法

def __new__(cls, a):
  return super().__new__(cls)

__new__是类方法,所以第一个参数也是cls,剩下的参数就是构造方法里需要的参数了。通常__new__都不需要定义,在元类编程中才需要,它可以控制类的生成过程。

__new__必须返回一个实例(instance),传入到__init__方法中的self参数,也就是实例变量。这里返回父类(object)的__new__方法用来创建一个新的实例。相当于

obj = object.__new__(MyClass)
obj = MyClass()

#obj是实例,上面两个方式等同

其中,MyClass是类,obj是实例(instance)

__init__方法

__new__是构造方法,那么__init__就是初始化函数,它负责将变量绑定到实例中,更新实例的__dict__字典。其中第一个参数self就是__new__的返回值,是类的实例。__new__方法先于__init__方法执行

def __init__(self, a):
  self.a = a

结合使用

class MyClass:
  def __new__(cls, a):
    return super().__new__(cls)

  def __init__(self, a):
    self.a = a
obj = MyClass(3)
print(obj.a)

要点

1.__new__是构造方法,__init__是初始化函数。
2.__new__通常不需要手动定义,一般在元类编程中使用,控制类的生成过程。
3.__new__第一个被执行,然后执行__init__绑定实例变量。
4.__new__必须有返回值,返回值是该类的实例,它会被__init__函数接收,通常叫做self变量

总结

以上所述是小编给大家介绍的Python中使用__new__实现单例模式并解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
python共享引用(多个变量引用)示例代码
Dec 04 Python
python:socket传输大文件示例
Jan 18 Python
Python IDLE 错误:IDLE''s subprocess didn''t make connection 的解决方案
Feb 13 Python
Python Flask基础教程示例代码
Feb 07 Python
python保存数据到本地文件的方法
Jun 23 Python
使用pandas read_table读取csv文件的方法
Jul 04 Python
Python pyinotify模块实现对文档的实时监控功能方法
Oct 13 Python
python3利用ctypes传入一个字符串类型的列表方法
Feb 12 Python
浅谈pytorch grad_fn以及权重梯度不更新的问题
Aug 20 Python
Python进程的通信Queue、Pipe实例分析
Mar 30 Python
Python smtp邮件发送模块用法教程
Jun 15 Python
Python爬虫爬取全球疫情数据并存储到mysql数据库的步骤
Mar 29 Python
pyQt5实时刷新界面的示例
Jun 25 #Python
Pandas之MultiIndex对象的示例详解
Jun 25 #Python
Python+threading模块对单个接口进行并发测试
Jun 25 #Python
python简单鼠标自动点击某区域的实例
Jun 25 #Python
详解pandas删除缺失数据(pd.dropna()方法)
Jun 25 #Python
python命令行参数用法实例分析
Jun 25 #Python
PyQt5重写QComboBox的鼠标点击事件方法
Jun 25 #Python
You might like
php使用socket post数据到其它web服务器的方法
2015/06/02 PHP
thinkPHP框架实现的简单计算器示例
2018/12/07 PHP
在JavaScript中监听IME键盘输入事件
2011/05/29 Javascript
Javascript 面向对象编程(coolshell)
2012/03/18 Javascript
js中点击空白区域时文本框与隐藏层的显示与影藏问题
2013/08/26 Javascript
JS关键字球状旋转效果的实例代码
2013/11/29 Javascript
为什么Node.js会这么火呢?Node.js流行的原因
2014/12/01 Javascript
js时间日期格式化封装函数
2014/12/02 Javascript
javascript中几个容易混淆的概念总结
2015/04/14 Javascript
js+html5获取用户地理位置信息并在Google地图上显示的方法
2015/06/05 Javascript
纯javascript实现的小游戏《Flappy Pig》实例
2015/07/27 Javascript
配置Grunt的Task时通配符支持和动态生成文件名问题
2015/09/06 Javascript
Javascript实现鼠标框选操作  不是点击选取
2016/04/14 Javascript
使用递归遍历对象获得value值的实现方法
2016/06/14 Javascript
js实现简单数字变动效果
2017/11/06 Javascript
vue2.0 资源文件assets和static的区别详解
2018/04/08 Javascript
node实现生成带参数的小程序二维码并保存到本地功能示例
2018/12/05 Javascript
Vue组件教程之Toast(Vue.extend 方式)详解
2019/01/27 Javascript
Vue指令v-for遍历输出JavaScript数组及json对象的常见方式小结
2019/02/11 Javascript
Vue 3.0双向绑定原理的实现方法
2019/10/23 Javascript
electron+vue实现div contenteditable截图功能
2020/01/07 Javascript
vue 插槽简介及使用示例
2020/11/19 Vue.js
python操作gmail实例
2015/01/14 Python
浅谈Python实现2种文件复制的方法
2018/01/19 Python
Python管理Windows服务小脚本
2018/03/12 Python
Pycharm在创建py文件时,自动添加文件头注释的实例
2018/05/07 Python
python如何创建TCP服务端和客户端
2018/08/26 Python
python基础 range的用法解析
2019/08/23 Python
Django1.11配合uni-app发起微信支付的实现
2019/10/12 Python
澳大利亚潮流尖端的快时尚品牌:Cotton On
2016/09/26 全球购物
盛大二次面试题
2016/11/18 面试题
摄影专业毕业生求职信
2014/03/13 职场文书
二年级小学生评语
2014/04/21 职场文书
重温入党誓词主持词
2015/06/29 职场文书
2016年重阳节慰问信
2015/12/01 职场文书
《艾尔登法环》1.03.3补丁上线 碎星伤害调整
2022/04/06 其他游戏