昨天碰到的问题。当写一个单例模式的时候,可以在init函数里面进行类对象的创建,然后对该对象进行初始化。详情如下:
class A(object):
_in1 = None
__in2 = None
instance = None
def __init__(self, a):
# 若是不使用__new__函数来写单例模式,在__init__函数中添加想关代码
if not self.instance:
self.instance = object.__new__(A)
self._a = a
self.b = 123
self.__c = 12345
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
if __name__ == "__main__":
a = A(12)
print(a._a)
b = A(13)
print(a._a, b._a)
print(a.instance)
print(b.instance)
#输出结果
'''
#未注释new函数
(base) F:\githubfiles\PythonAutoTest>D:/mysw/conda/python.exe f:/githubfiles/PythonAutoTest/others/trans_test.py
12
13 13
<__main__.A object at 0x0000022DFFA23190>
<__main__.A object at 0x0000022DFFA23190>
#注释掉new函数
(base) F:\githubfiles\PythonAutoTest>D:/mysw/conda/python.exe f:/githubfiles/PythonAutoTest/others/trans_test.py
12
12 13
<__main__.A object at 0x0000021E46153190>
<__main__.A object at 0x0000021E463F3430>
'''
在未注释掉__new__函数的时候,a和b初始化后的对象是一个,通过输出a._a和b._b对象及他们的instance对象能看出。
在注释掉__new__函数后,a和b对应的是两个对象。
因为cls是对应的类A,self对应的是类A的实例化对象,它们两个都能取到类前面声明的instance对象。
由于new函数是创建类对象的时候调用的,当一个类被创建的时候,会判断instance有没有被创建,有的话则返回instance,没有的话创建一个。
而在init函数里面,当调用到init函数的时候,已经通过默认的new函数创建了一个新的类对象了,所以此时是不会有再去判断instance有没有以及创建,对于当前对象来说并没有太大关系,instance此时只是这个类对象内的一个属性。
故而由于两个类对象时不同的两个对象,所以其内部的属性值也不会相同,故输出的值并不相同。
当然,也可以通过类的装饰器来实现所谓的单例模式:
instances = {}
def singleton(cls):
def getinstance(*args, **kwargs):
if not instances.get(cls):
instance = cls(*args, **kwargs)
instances[cls] = instance
return instances[cls]
return getinstance
如上面代码所示,当一个类要被执行的时候,这个装饰器会先判断之前有没有初始化过这个类,若是有的话,则直接返回之前初始化后的对象,若是没有的话,则返回初始化一个对象,并将新对象添加到缓存中。
当然,上面这个单例模式的装饰器,新申请创建的类的属性值会按照这个类第一次被初始化时候的值。由于*args是非键值对的,**kwargs也有可能与类内属性并非一一对应关系,所以,新传的参数值没法改变之前的值。
但是,具体问题具体分析,比如说一个数据库连接的类,可以定义一个refresh函数,将新传的参数传给它,令它来更新类内的属性值。
另外,从上面的代码运行中看到,在类中,无论是类内包含的__in2,还是init里初始化的属性__c,由于它们前面有两个下划线,在类中,Python自动在它们前面添加了"-类名",对于前面的例子,它们分别被改为_A__in2 和 _A__c