Python类内的cls和self,及单例模式的探究

昨天碰到的问题。当写一个单例模式的时候,可以在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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值