zoukankan      html  css  js  c++  java
  • day27_面向对象进阶

    飒飒

    六、描述符

    1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
    __get__():调用一个属性时,触发
    __set__():为一个属性赋值时,触发
    __delete__():采用del删除属性时,触发

    class Foo: #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
        def __get__(self, instance, owner):
            pass
        def __set__(self, instance, value):
            pass
        def __delete__(self, instance):
            pass
    定义一个描述符

    2 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

    class Foo:
        def __get__(self, instance, owner):
            print('触发get')
        def __set__(self, instance, value):
            print('触发set')
        def __delete__(self, instance):
            print('触发delete')
    
    #包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法
    f1=Foo()
    f1.name='egon'
    f1.name
    del f1.name
    #疑问:何时,何地,会触发这三个方法的执行
    引子:描述符类产生的实例进行属性操作并不会触发三个方法的执行
    #描述符Str
    class Str:
        def __get__(self, instance, owner):
            print('Str调用')
        def __set__(self, instance, value):
            print('Str设置...')
        def __delete__(self, instance):
            print('Str删除...')
    
    #描述符Int
    class Int:
        def __get__(self, instance, owner):
            print('Int调用')
        def __set__(self, instance, value):
            print('Int设置...')
        def __delete__(self, instance):
            print('Int删除...')
    
    class People:
        name=Str()
        age=Int()
        def __init__(self,name,age): #name被Str类代理,age被Int类代理,
            self.name=name
            self.age=age
    
    #何地?:定义成另外一个类的类属性
    
    #何时?:且看下列演示
    
    p1=People('alex',18)
    
    #描述符Str的使用
    p1.name
    p1.name='egon'
    del p1.name
    
    #描述符Int的使用
    p1.age
    p1.age=18
    del p1.age
    
    #我们来瞅瞅到底发生了什么
    print(p1.__dict__)
    print(People.__dict__)
    
    #补充
    print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的
    print(type(p1).__dict__ == People.__dict__)
    描述符应用之何时?何地?

    3 描述符分两种
    一 数据描述符:至少实现了__get__()和__set__()

    1class Foo:
    2     def __set__(self, instance, value):
    3         print('set')
    4     def __get__(self, instance, owner):
    5         print('get')

    二 非数据描述符:没有实现__set__()

    1 class Foo:
    2     def __get__(self, instance, owner):
    3         print('get')
    class Foo:
        name=2
        def __get__(self, instance, owner):
            print('get方法')
            print(instance)
            print(owner)
        def __set__(self, instance, value):
            print('set方法',value)
            print(instance)
            #instance.__dict__[self]=value  #b1.__dict__
            instance.__dict__['x'] = value
        def __delete__(self, instance):
            print('del方法')
            print(instance)
    class Bar:
        x=Foo()   #必须把描述符定义成这个的类属性。也就是描述符的一个对象
        def __init__(self,n):
            self.x=n   #x的属性被描述符代理,通通触发Foo的set方法
    b1=Bar(10)
    #b1.x   #另外一个类产生的实例,一调用x的属性,也就是foo的一个实例。就触发了描述符的get方法
    b1.x=2
    b1.y=22
    print(b1.__dict__)
    
    >>>
    set方法 10
    <__main__.Bar object at 0x10207e780>
    set方法 2
    <__main__.Bar object at 0x10207e780>
    {'x': 2, 'y': 22}

    4 注意事项:
    一 描述符本身应该定义成新式类,被代理的类也应该是新式类
    二 必须把描述符定义成另外一个类的类属性,不能为定义到构造函数中
    三 要严格遵循该优先级,优先级由高到底分别是
    1.类属性   Bar.x  操作的是自己的属性字典,和数据属性统一级别,存在更新覆盖.
    2.数据描述符
    3.实例属性     b1.x  现在自己的属性字典里面找,找不到,再到类的属性字典里面找---找到的是X对应的Foo()的对象。自然调到描述符去了。
    4.非数据描述符
    5.找不到的属性触发__getattr__()

    #描述符Str
    class Str:
        def __get__(self, instance, owner):
            print('Str调用')
        def __set__(self, instance, value):
            print('Str设置...')
        def __delete__(self, instance):
            print('Str删除...')
    
    class People:
        name=Str()
        def __init__(self,name,age): #name被Str类代理,age被Int类代理,
            self.name=name
            self.age=age
    
    
    #基于上面的演示,我们已经知道,在一个类中定义描述符它就是一个类属性,存在于类的属性字典中,而不是实例的属性字典
    
    #那既然描述符被定义成了一个类属性,直接通过类名也一定可以调用吧,没错
    People.name #恩,调用类属性name,本质就是在调用描述符Str,触发了__get__()
    
    People.name='egon' #那赋值呢,我去,并没有触发__set__()
    del People.name #赶紧试试del,我去,也没有触发__delete__()
    #结论:描述符对类没有作用-------->傻逼到家的结论
    
    '''
    原因:描述符在使用时被定义成另外一个类的类属性,因而类属性比二次加工的描述符伪装而来的类属性有更高的优先级
    People.name #恩,调用类属性name,找不到就去找描述符伪装的类属性name,触发了__get__()
    
    People.name='egon' #那赋值呢,直接赋值了一个类属性,它拥有更高的优先级,相当于覆盖了描述符,肯定不会触发描述符的__set__()
    del People.name #同上
    '''
    类属性>数据描述符
    #描述符Str
    class Str:
        def __get__(self, instance, owner):
            print('Str调用')
        def __set__(self, instance, value):
            print('Str设置...')
        def __delete__(self, instance):
            print('Str删除...')
    
    class People:
        name=Str()
        def __init__(self,name,age): #name被Str类代理,age被Int类代理,
            self.name=name
            self.age=age
    
    
    p1=People('egon',18)
    
    #如果描述符是一个数据描述符(即有__get__又有__set__),那么p1.name的调用与赋值都是触发描述符的操作,于p1本身无关了,相当于覆盖了实例的属性
    p1.name='egonnnnnn'
    p1.name
    print(p1.__dict__)#实例的属性字典中没有name,因为name是一个数据描述符,优先级高于实例属性,查看/赋值/删除都是跟描述符有关,与实例无关了
    del p1.name
    数据描述符>实例属性
    class Foo:
        def func(self):
            print('我胡汉三又回来了')
    f1=Foo()
    f1.func() #调用类的方法,也可以说是调用非数据描述符
    #函数是一个非数据描述符对象(一切皆对象么)
    print(dir(Foo.func))
    print(hasattr(Foo.func,'__set__'))
    print(hasattr(Foo.func,'__get__'))
    print(hasattr(Foo.func,'__delete__'))
    #有人可能会问,描述符不都是类么,函数怎么算也应该是一个对象啊,怎么就是描述符了
    #笨蛋哥,描述符是类没问题,描述符在应用的时候不都是实例化成一个类属性么
    #函数就是一个由非描述符类实例化得到的对象
    #没错,字符串也一样
    
    
    f1.func='这是实例属性啊'
    print(f1.func)
    
    del f1.func #删掉了非数据
    f1.func()
    实例属性>非数据描述符
    class Foo:
        def func(self):
            print('我胡汉三又回来了')
    
        def __getattr__(self, item):
            print('找不到了当然是来找我啦',item)
    f1=Foo()
    
    f1.xxxxxxxxxxx
    非数据描述符>找不到

    5 描述符使用

    day28

    6、软件开发规范

    总结:

    #自省
    hasattr(obj,'属性') #obj.属性 是否存在
    getattr(obj,'属性') #获取obj.属性 不存在则报错
    getattr(obj,'属性','默认值') #获取obj.属性 不存在不会报错,返回那个默认值
    setattr(obj,'属性','属性的值') #obj.属性=属性的值
    delattr(obj,'属性') #del obj.属性

    #__getattr__,__setattr__,__delattr__
    obj点的方式去操作属性时触发的方法

    __getattr__:obj.属性 不存在时触发
    __setattr__:obj.属性=属性的值 时触发
    __delattr__:del obj.属性 时触发

    #__getitem__,__setitem_,__delitem__
    obj[‘属性’]的方式去操作属性时触发的方法

    __getitem__:obj['属性'] 时触发
    __setitem__:obj['属性']=属性的值 时触发
    __delitem__:del obj['属性'] 时触发

    #__get__,__set__,__delete__
    描述就是一个新式类,这个类至少要实现上述三个方法的一个
    class 描述符:
    def __get__():
    pass
    def __set__():
    pass
    def __delete__():
    pass

    class 类:
    name=描述符()

    obj=类()
    obj.name #get
    obj.name='egon' #set
    del obj.name #delete

    #__del__:析构方法
    垃圾回收时触发

  • 相关阅读:
    ApacheShiro反序列化远程代码执行 漏洞处理
    js判断是电脑(pc)访问还是手机(mobile)访问
    MySQL实现主从库,AB复制配置
    js实现回到顶部功能
    JAVA结合Redis处理缓存穿透问题
    Apache Shiro使用官方自带的生成AES密钥
    JAVA将Object数组转换为String数组
    JAVA中数组(Array)、字符串(String)、集合(List、Set)相互转换
    输入npm install 报错npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! node-sass@4.13.1 postinstall: `node scripts/build.js`
    tomcat的部署jspgou+优化
  • 原文地址:https://www.cnblogs.com/laixiaoyun/p/6233964.html
Copyright © 2011-2022 走看看