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基于xmlrpc实现二进制文件传输的方法
Jun 02 Python
Python操作csv文件实例详解
Jul 31 Python
解决Pycharm下面出现No R interpreter defined的问题
Oct 29 Python
解决PyCharm的Python.exe已经停止工作的问题
Nov 29 Python
Python功能点实现:函数级/代码块级计时器
Jan 02 Python
python读取文件名并改名字的实例
Jan 07 Python
Python3使用Matplotlib 绘制精美的数学函数图形
Apr 11 Python
Python生成个性签名图片获取GUI过程解析
Dec 16 Python
Python基于jieba, wordcloud库生成中文词云
May 13 Python
python给视频添加背景音乐并改变音量的具体方法
Jul 19 Python
Python-openpyxl表格读取写入的案例详解
Nov 02 Python
Python实现Matplotlib,Seaborn动态数据图
May 06 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语法(4)
2006/10/09 PHP
谈谈PHP语法(2)
2006/10/09 PHP
php中的一些数组排序方法分享
2012/07/20 PHP
php中define用法实例
2015/07/30 PHP
PHP中list方法用法示例
2016/12/01 PHP
php微信公众号开发之翻页查询
2018/10/20 PHP
PHP封装mysqli基于面向对象的mysql数据库操作类与用法示例
2019/02/25 PHP
Jquery 动态添加按钮实现代码
2010/05/06 Javascript
JavaScript Memoization 让函数也有记忆功能
2011/10/27 Javascript
javascript中不提供sleep功能如何实现这个功能
2014/05/27 Javascript
禁止iframe脚本弹出的窗口覆盖了父窗口的方法
2014/09/06 Javascript
兼容主流浏览器的jQuery+CSS 实现遮罩层的简单代码
2014/10/14 Javascript
完美兼容各大浏览器的jQuery仿新浪图文淡入淡出间歇滚动特效
2014/11/12 Javascript
javascript引用类型指针的工作方式
2015/04/13 Javascript
详解JavaScript中setSeconds()方法的使用
2015/06/11 Javascript
浏览器兼容的JS写法总结
2016/04/27 Javascript
学习Angularjs分页指令
2016/07/01 Javascript
javascript 动态样式添加的简单实现
2016/10/11 Javascript
Kindeditor单独调用多图上传实例
2017/07/31 Javascript
浅谈VUE监听窗口变化事件的问题
2018/02/24 Javascript
解决Nodejs全局安装模块后找不到命令的问题
2018/05/15 NodeJs
JS判断字符串是否为整数的方法--简单的正则判断
2018/07/23 Javascript
jQuery实现的网站banner图片无缝轮播效果完整实例
2019/01/28 jQuery
js+html实现点名系统功能
2019/11/05 Javascript
简单讲解Python中的数字类型及基本的数学计算
2016/03/11 Python
Python序列操作之进阶篇
2016/12/08 Python
python实现杨辉三角思路
2017/07/14 Python
python自动化测试之DDT数据驱动的实现代码
2019/07/23 Python
基于python使用tibco ems代码实例
2019/12/20 Python
Oakley西班牙官方商店:太阳眼镜和男女运动服
2019/04/26 全球购物
香港艺人陈冠希创办的潮流品牌:JUICESTORE
2021/03/04 全球购物
爱岗敬业演讲稿范文
2014/01/14 职场文书
2014年社区植树节活动方案
2014/02/28 职场文书
竞选学习委员演讲稿
2014/09/01 职场文书
干货分享:推荐信写作技巧!
2019/06/21 职场文书
MySQL 逻辑备份与恢复测试的相关总结
2021/05/14 MySQL