zoukankan      html  css  js  c++  java
  • 十八.描述符(__get__,__set__,__delete__)

    描述符(__get__,__set__,__delete__)

    4 注意事项:
    一 描述符本身应该定义成新式类,被代理的类也应该是新式类
    二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
    三 要严格遵循该优先级,优先级由高到底分别是
    1.类属性
    2.数据描述符
    3.实例属性
    4.非数据描述符
    5.找不到的属性触发__getattr__()
    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__)
    # 描述符应用之何时?何地?三个方法的执行
    # 执行顺序
    # Str设置...
    # Int设置...
    # Str调用
    # Str设置...
    # Str删除...
    # Int调用
    # Int设置...
    # Int删除...
    # {}
    # {'__module__': '__main__', 'name': <__main__.Str object at 0x00000177DAFD5048>, 'age': <__main__.Int object at 0x00000177DAFD5080>, '__init__': <function People.__init__ at 0x00000177DAFCAEA0>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
    # True
    # True

    二 .描述符分两种

      1.  数据描述符:至少实现了__get__()和__set__()

    一 数据描述符:至少实现了__get__()和__set__()
    
    1 class Foo:
    2     def __set__(self, instance, value):
    3         print('set')
    4     def __get__(self, instance, owner):
    5         print('get')


    # 实例属性是低于 数据描述符   所以优先找的是描述符属性   优先级

    class Foo:
    def __set__(self, instance, value):
    print('set')
    print(value)
    def __get__(self, instance, owner):
    print('get')
    print(owner)
    class Per(object):
    name=Foo()
    def __init__(self,name):
    self.name=name
    def aa(self):
    print(self.name)

    f=Per("李四")
    f.name
    f.aa()
    #
    # get
    # <class '__main__.Per'>
    # get
    # <class '__main__.Per'>
    # None




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

    1 class Foo:
    2     def __get__(self, instance, owner):
    3         print('get')



    # 实例属性是高于 非数据描述符   所以优先找的是实例属性    这就是优先级
    class Foo:
    def __get__(self, instance, owner):
    print('get')
    class Per(object):
    name=Foo()
    def __init__(self,name):
    self.name=name
    def aa(self):
    print(self.name)
    f=Per("李四")
    print(f.name)
    print(f.__dict__)
    print(Per.__dict__)

    # 李四
    # {'name': '李四'}
    # {'__module__': '__main__', 'name': <__main__.Foo object at 0x00000268526C8860>, '__init__': <function Per.__init__ at 0x00000268526CABF8>, 'aa': <function Per.aa at 0x00000268526CAD08>, '__dict__': <attribute '__dict__' of 'Per' objects>, '__weakref__': <attribute '__weakref__' of 'Per' objects>, '__doc__': None}

     案例

    众所周知,python是弱类型语言,即参数的赋值没有类型限制,下面我们通过描述符机制来实现类型限制功能
    # 这是利用描述符来 来做 实例化属性 类型的判断
    class Typed:
        def __init__(self,name,expected_type):
            self.name=name
            self.expected_type=expected_type
        def __get__(self, instance, owner):
            if instance is None:
                return self
            return instance.__dict__[self.name]
        def __set__(self, instance, value):
            if not isinstance(value,self.expected_type):
                raise TypeError('Expected %s' %str(self.expected_type))
            instance.__dict__[self.name]=value
        def __delete__(self, instance):
            instance.__dict__.pop(self.name)
    # 这是利用描述符来 来做 实例化属性 类型的判断
    class People:
        name=Typed('name',str)
        age=Typed('age',int)
        salary=Typed('salary',float)
    
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
    
        def aa(self):
            print(self.name)
    p1=People('张三',18,3333.3)
    print(p1.__dict__)
    p1.aa()
  • 相关阅读:
    Celery
    MongoDB-简介
    人工智障
    Flask-session,WTForms,POOL,Websocket通讯原理 -握手,加密解密过程
    web-socket
    flask基础2
    flask的基础1
    项目部署
    nginx简单学习
    redis的安装与配置
  • 原文地址:https://www.cnblogs.com/Sup-to/p/11087506.html
Copyright © 2011-2022 走看看