美文网首页python自学
[Python] 使用new构造单例模式

[Python] 使用new构造单例模式

作者: 敲代码的密斯想 | 来源:发表于2018-03-09 11:42 被阅读27次
1. self 和 cls

首先来简要介绍一下类中的self和cls,如下栗:

class A(object):
 def foo1(self):
    print("Hello", self)

 @classmethod
 def foo2(cls):
    print("Hello", cls)

调用foo1:

>>>a = A()
>>>a.foo1()
Hello <__main__.A object at 0x1040263c8>
>>>print(a)
Hello <__main__.A object at 0x1040263c8>

可以发现self和实例a指向了同一个对象,再调用类方法foo2:

>>>A.foo2()
Hello <class '__main__.A'>

发现此时指向的就是A类本身,从这个栗子我们可以得出,self指向了实例化对象而cls指向了类本身。

2. __init____new__

我们再来看一下__init__,相信大家对__init__已经很熟悉了,__init__通常用于初始化一个类实例,如下例:

class A(object):
   def __init__(self, x, y):
       self.x = x
       self.y = y

由于它是初始化一个类实例的,所有需要传入self。

那么__new__方法又是做什么用的呢?看下面的栗子:

class A(object):
    def __init__(self, x, y):
        print('__init__ has been called')
        self.__x = x
        self.__y = y

    def __new__(cls, *args, **kwargs):
        print('__new__ has been called')
        return super(A, cls).__new__(cls, *args, **kwargs)

    def __str__(self):
        return 'A : x is {}, y is {}'.format(self.__x, self.__y)

这里有个小插曲,当我尝试实例化A类,并将其传入参数x,y时,报了以下错误:

>>>tt=A('xxx','yyy')

in __new__
    return super(A, cls).__new__(cls, *args, **kwargs)
TypeError: object() takes no parameters

仔细阅读报的错,发现是由于__new__返回的是父类实例化后的对象的—__new__方法,而父类object__new__方法不接受任何参数,可我却对其传了参。解决方法就是不对父类实例化的对象的__new__方法传参,将上述__new__方法改成如下:

    def __new__(cls, *args, **kwargs):
        print('__new__ has been called')
        return super(A, cls).__new__(cls)

再次运行

>>>tt=A('xxx','yyy')
>>>print(tt)

__new__ has been called
__init__ has been called
A : x is xxx, y is yyy

一切都平静了,可以看到,当实例化对象时,先是调用了__new__,然后才调用了__init__进行了初始化。其中__new__方法中可以return父类__new__出来的实例,也可以直接将其他类__new__出来的实例返回(但这就意义不大了)。
那可不可以调用自身的__new__来制造实例呢?当然不行,因为这会造成死循环(一定要避免return cls.__new__(cls))。

新式类(最终继承到object)开始实例化时,__new__会返回一个实例,然后该类的__init__方法作为构造方法回接收这个实例(即self)作为自己的第一个参数,然后依次传入__new__方法中接收的其它参数。

如果 __new__并未返回实例,那么当前类的__init__方法是不会被调用的。

3. 使用__new__构造单例模式

说了那么多,__new__方法到底有什么作用呢?接下来介绍一下如何使用它来创建单例模式。

单例模式简单来说就是即一个类只有一个实例,看下面的栗子:

class A(object):
    _a = {}

    def __new__(cls, *args, **kwargs):
        ob = super(A, cls).__new__(cls)
        ob.__dict__ = cls._a
       
        return ob

实例化A,赋给a,并向_a添加新的键值对:

>>>a = A()
>>>a._a['a'] = 1

再次实例化A,赋给b,查看b的__dict__

>>>b = A()
>>>print(b.__dict__)
{'a':1}
>>>print(b.a)
1

居然有先前实例a的属性,而且居然还可以直接调用!
我们将实例b也赋予一些属性,并尝试通过实例a去调用:

>>>b.b=2
>>>print(a.b)
2

仿佛实例a与实例b成了同一个实例,只是有了两个名字!这就实现了单例模式。
我们来看一下上面的代码,__dict__是用来存储对象属性的一个字典,在A类中我们创建了一个空字典_a并将其传入__dict__,由于字典恰好是可变对象,所以当我们对任何A的实例添加属性进入__dict__时,_a也进行了更新,可以说_a中保存了最新的所有的A对象的属性键值对。将_a赋给实例的__dict__,每个实例也就拥有了同一个__dict__,真是神奇。

于此类似的,利用__new__构建单例模式还有一种方法,如下栗:

class Singleton(object):
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance

class MyClass(Singleton):
    a = 1

具体的实现原理就不做赘述啦,相信读到这里你一定可以理解~

相关文章

  • python单例模式

    python单例模式实现方式 使用模板 python模块是天然的单例模式(.pyc文件的存在) 使用__new__...

  • [Python] 使用new构造单例模式

    1. self 和 cls 首先来简要介绍一下类中的self和cls,如下栗: 调用foo1: 可以发现self和...

  • python中OOP的单例

    目录 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 单例

    目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • python 单例

    仅用学习参考 目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计...

  • 2018-10-08 Python20 __方法__、单例模式

    __方法__: 运行: 单例模式: 运行: Python的构造方法相当于:既调__new__方法、又调__init...

  • 通过模块功能实现单例模式

    一般说到python实现单例模式,都会想到各种装饰器的途径来构造 装饰器途径构造单例模式参考文档:python装饰...

  • python 的单例模式

    python设计模式中的 单例模式:单例模式可以通过__new__ 方法实现,而__new__ 方法一般用于继承不...

  • Python 面向对象7: 单例模式

    一、内容 1.1、单例设计模式 1.2、__new__方法 1.3、Python 中的单例 二、单例设计模式 2....

  • Kotlin带参数的单例

    单例包装类 使用如下 无参构造函数的单例模式

网友评论

    本文标题:[Python] 使用new构造单例模式

    本文链接:https://www.haomeiwen.com/subject/faspfftx.html