Python类中的单例模式和描述符

359 阅读2分钟

「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战

new方法会开辟空间
每次实例化,这个new方法都会开辟一个新的空间
可不可以让这new方法只开辟一个空间:::单例模式

单例模式:

提前引入一些小知识点:::
第一个:

hasattr() #has attribute
hasattr() 函数用于判断对象是否包含对应的属性\
hasattr(object(对象),name("字符串,属性名"))
返回True(有的时候) False(没有的时候)

class Person:
    #范式:固定的公式;固定的写法
    def __new__(cls,*args,**kwargs):
        #hasattr 判断类里面有没有这个方法
        #如果类没有instance这个属性
        if not hasattr(cls,'instance'):    #cls就是Person这个类本身
            #没有instance这个属性就会执行下面这句
            #创建instance这个属性,等于父类的new方法
            #new返回父类的new方法,和返回instance都可以
            cls.instance = super().__new__(cls)           #上面说如果类没有instance这个属性就执行这句,把父类的new方法添加为类本身的属性
                                                                                                  #在下一句在return这个类本身的这个instance属性,这样在第二次实例化的时候,return
                                                                                                  #的仍然是第一次实例化的cls.instance,就没有返回父类的new方法,也就没有创建新的内存
                                                                                                  #空间,而是仍然指向第一次创建的内存空间
        return cls.instance        #如果把返回的改为 super().__new__(cls),直接返回父类的new方法,这就不是单例模式,因为每次实例化都会返回父类
                                                           #的new方法,即创建一个新的内存空间。
    def __init__(self,name):
        self.name = name

a = Person('寒沙')
b = Person('敢敢')
print(id(a))
print(id(b))                         

会发现两次的id都一样了,即两次指向同一片内存空间,相当于a被b覆盖了。
意味着这两个其实引用的是同一个实例,是一个实例的不同名字

描述符

描述符协议:python描述符是一个“绑定行为”的对象属性,在描述符协议中,
它可以通过方法重写属性的访问。这些方法有__get__(), set(), 和__delete__()。
如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符

举例说明: 描述符:描述符就是类里面的属性base
控制实例对象a访问 这个属性 (base) 可以做一些额外的操作
描述符 定义了__get__ set delete 当中的一种

class Base:
    def __get__(self,instance,owner):
        print('恭喜玩家获得荒古宝典')
    def __set__(self, instance,value):
        print('强化%s'%value)
    def __delete__(self,instance):
        print('武器已经损坏')

class A:
    base = Base()

#实例化
a = A()

a.base           # __get__        会直接输出__get__方法里面的内容

a.base = 50      # __set__ 		  会直接输出__set__方法里面的内容

del a.base       # __delete__	  会直接输出__delete__方法里面的内容