由Python通过__new__实现单例模式,所想到的__new__和__init__方法的区别

Posted 潇湘旧友

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了由Python通过__new__实现单例模式,所想到的__new__和__init__方法的区别相关的知识,希望对你有一定的参考价值。

        之前通过读书,了解到在Python中可以通过__new__方法来实现单例模式,代码一个示例如下,我就有了几个疑问,什么是单例模式?__new__方法是用来做什么的?用__new__方法实现的单例模式,比如下面的MyClass类,会对类的初始化有影响吗?会对类的实例方法、类方法、静态方法有影响吗?下面会说下我对这些概念的理解,如有错误,欢迎交流指出,在此表示感谢。

 1 class SingleTon(object):
 2     _instance = {}
 3 
 4     def __new__(cls, *args, **kwargs):
 5         if cls not in cls._instance:
 6             cls._instance[cls] = super(SingleTon, cls).__new__(cls, *args, **kwargs)
 7         print cls._instance
 8         return cls._instance[cls]
 9 
10 
11 class MyClass(SingleTon):
12     class_val = 22

 

      首先说下单例模式,单例模式是确保一个类只有一个实例,并且这个实例是自己创造的,在系统中用到的都是这个实例。单例模式是设计模式的一种,关于设计模式和单例模式更具体的内容,可以查看相关的书本,在后面我也要好好学习一下这些东西。

 

    下面主要说下__new__是用来干什么的,在Python中,__new__是用来创造一个类的实例的,而__init__是用来初始化这个实例的。既然__new__用来创造实例,也就需要最后返回相应类的实例,那么如果返回的是其他类的实例,结果如何呢?见下面的代码。以下代码运行后,首先打印出NoReturn __new__然后打印出other instance,最后通过type(t)可以看到t的类型是<class ‘__main__.Other‘>,可以知道如果__new__中不返回本类的实例的话,是没法调用__init__方法的。想要返回本类的实例,只需要把以下代码中12行的Other()改成super(NoReturn, cls).__new__(cls, *args, **kwargs)即可。

 

 1 class Other(object):
 2     val = 123
 3 
 4     def __init__(self):
 5         print other instance
 6 
 7 
 8 class NoReturn(object):
 9 
10     def __new__(cls, *args, **kwargs):
11         print NoReturn __new__
12         return Other()
13 
14     def __init__(self, a):
15         print a
16         print NoReturn __init__
17 
18 t = NoReturn(12)
19 print type(t)

       

       最后来说用__new__方法实现的单例模式,会对实例方法,类方法,静态方法,实例变量和类变量有影响吗?答案是对相应的方法是没有影响的,但是如果用不同的变量都初始化了这个实例,在后面的变量中修改实例变量和类变量的话,前面的也会相应修改,而这也正好符合单例,无论多少个变量指向了这个实例,他们指向的是同一个。在__new__中产生完实例后,每次初始化实例对象,都是产生的同一个实例,而这个实例中相关的方法、变量还是和普通的实例一样使用。测试代码以及输出如下:

 1 class MyClass(SingleTon):
 2     class_val = 22
 3 
 4     def __init__(self, val):
 5         self.val = val
 6 
 7     def obj_fun(self):
 8         print self.val, obj_fun
 9 
10     @staticmethod
11     def static_fun():
12         print staticmethod
13 
14     @classmethod
15     def class_fun(cls):
16         print cls.class_val, classmethod
17 
18 
19 if __name__ == __main__:
20     a = MyClass(1)
21     b = MyClass(2)
22     print a is b   # True
23     print id(a), id(b)  # 4367665424 4367665424
24     # 类型验证
25     print type(a)  # <class ‘__main__.MyClass‘>
26     print type(b)  # <class ‘__main__.MyClass‘>
27     # 实例方法
28     a.obj_fun()  # 2 obj_fun
29     b.obj_fun()  # 2 obj_fun
30     # 类方法
31     MyClass.class_fun()  # 22 classmethod
32     a.class_fun()  # 22 classmethod
33     b.class_fun()  # 22 classmethod
34     # 静态方法
35     MyClass.static_fun()  # staticmethod
36     a.static_fun()  # staticmethod
37     b.static_fun()  # staticmethod
38     # 类变量
39     a.class_val = 33
40     print MyClass.class_val  # 22
41     print a.class_val  # 33
42     print b.class_val  # 33
43     # 实例变量
44     print b.val  # 2
45     print a.val  # 2

 

以上是关于由Python通过__new__实现单例模式,所想到的__new__和__init__方法的区别的主要内容,如果未能解决你的问题,请参考以下文章

python中单例模式的实现-通过闭包函数和魔术方法__new__实现单例模式

Python——单例设计模式

python实现单例工厂模式

python设计模式之单例

python __new__方法与单例模式

Python中的单例设计模式__new__方法