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递归函数和河内塔问题
Apr 18 Python
Python中使用支持向量机(SVM)算法
Dec 26 Python
Python常用字符串替换函数strip、replace及sub用法示例
May 21 Python
Python实现获取本地及远程图片大小的方法示例
Jul 21 Python
详解Python 装饰器执行顺序迷思
Aug 08 Python
Python爬取商家联系电话以及各种数据的方法
Nov 10 Python
Python pip替换为阿里源的方法步骤
Jul 02 Python
使用python对多个txt文件中的数据进行筛选的方法
Jul 10 Python
django 中QuerySet特性功能详解
Jul 25 Python
pygame实现俄罗斯方块游戏(AI篇2)
Oct 29 Python
Python调用Windows API函数编写录音机和音乐播放器功能
Jan 05 Python
全网最全python库selenium自动化使用详细教程
Jan 12 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学习之运算符相关概念
2011/06/09 PHP
PHP读取PDF内容配合Xpdf的使用
2012/11/24 PHP
PHP中new static()与new self()的区别异同分析
2014/08/22 PHP
smarty模板数学运算示例
2016/12/11 PHP
thinkphp5.0自定义验证规则使用方法
2017/11/16 PHP
基于 Swoole 的微信扫码登录功能实现代码
2018/01/15 PHP
Laravel统计一段时间间隔的数据方法
2019/10/09 PHP
javascript offsetX与layerX区别
2010/03/12 Javascript
jQuery之ajax技术的详细介绍
2013/06/19 Javascript
javascript中String对象的slice()方法分析
2014/12/20 Javascript
解决node-webkit 不支持html5播放mp4视频的方法
2015/03/11 Javascript
jQuery插件multiScroll实现全屏鼠标滚动切换页面特效
2015/04/12 Javascript
JavaScript绑定事件监听函数的通用方法
2016/05/14 Javascript
JavaScript之iterable_动力节点Java学院整理
2017/06/29 Javascript
react-native ListView下拉刷新上拉加载实现代码
2017/08/03 Javascript
Vue单页面应用保证F5强刷不清空数据的解决方案
2018/01/31 Javascript
Vue组件开发技巧总结
2018/03/04 Javascript
vue实现自定义多选与单选的答题功能
2018/07/05 Javascript
为jquery的ajax请求添加超时timeout时间的操作方法
2018/09/04 jQuery
QRCode.js二维码生成并能长按识别
2018/10/16 Javascript
Vue 框架之动态绑定 css 样式实例分析
2018/11/14 Javascript
微信小程序 调用微信授权窗口相关问题解决
2019/07/25 Javascript
JavaScript实现多个物体同时运动
2020/03/12 Javascript
Javascript Symbol原理及使用方法解析
2020/10/22 Javascript
解决vant title-active-color与title-inactive-color不生效问题
2020/11/03 Javascript
Python使用combinations实现排列组合的方法
2018/11/13 Python
python3+PyQt5 数据库编程--增删改实例
2019/06/17 Python
win10下opencv-python特定版本手动安装与pip自动安装教程
2020/03/05 Python
canvas里面如何基于随机点绘制一个多边形的方法
2018/06/13 HTML / CSS
在什么时候需要使用"常引用"
2015/12/31 面试题
求职简历的自我评价怎样写好
2013/10/07 职场文书
建筑学推荐信
2013/11/03 职场文书
小学见习报告
2014/10/31 职场文书
小浪底导游词
2015/02/12 职场文书
晶体管来复再生式二管收音机
2021/04/22 无线电
Go本地测试解耦任务拆解及沟通详解Go本地测试的思路沟通的重要性总结
2022/06/21 Golang