zoukankan      html  css  js  c++  java
  • python学习之描述符


    class Foo:
    def __get__(self, instance, owner):
    print('===>get方法')
    def __set__(self, instance, value): #self相当于Foo对象,instance相当于b1实例对象,value等于10
    print('===>set方法',instance,value)
    instance.__dict__['x']=value #b1.__dict__
    def __delete__(self, instance):
    print('===>delete方法')


    class Bar:
    x=Foo() #在何地?这里定义了描述符对象(x被Foo代理)
    def __init__(self,n):
    self.x=n #b1.x=10
    b1=Bar(10)
    print(b1.__dict__)
    b1.x=11111111111111111
    print(b1.__dict__)

    b1.y=11111111111111111111111111111111111111
    print(b1.__dict__)

    由Bar类产生的实例,对x属性的调用,全部都去找Foo类

    4 注意事项:
    一 描述符本身应该定义成新式类,被代理的类也应该是新式类
    二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
    三 要严格遵循该优先级,优先级由高到底分别是
    1.类属性

    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 #同上
    '''

    2.数据描述符
    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

    3.实例属性

    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 #删掉了非数据

    4.非数据描述符

    class Foo:
    def __set__(self, instance, value):
    print('set')
    def __get__(self, instance, owner):
    print('get')
    class Room:
    name=Foo()
    def __init__(self,name,width,length):
    self.name=name
    self.width=width
    self.length=length


    #name是一个数据描述符,因为name=Foo()而Foo实现了get和set方法,因而比实例属性有更高的优先级
    #对实例的属性操作,触发的都是描述符的
    r1=Room('厕所',1,1)
    r1.name
    r1.name='厨房'

    class Foo:
    def __get__(self, instance, owner):
    print('get')
    class Room:
    name=Foo()
    def __init__(self,name,width,length):
    self.name=name
    self.width=width
    self.length=length


    #name是一个非数据描述符,因为name=Foo()而Foo没有实现set方法,因而比实例属性有更低的优先级
    #对实例的属性操作,触发的都是实例自己的
    r1=Room('厕所',1,1)
    r1.name
    r1.name='厨房'

    5.找不到的属性触发__getattr__()
    class Foo:
    def func(self):
    print('我胡汉三又回来了')

    def __getattr__(self, item):
    print('找不到了当然是来找我啦',item)
    f1=Foo()

    f1.xxxxxxxxxxx

  • 相关阅读:
    20199106 2019-2020-2 《网络攻防实践》第三周作业
    Vulnhub
    NEEPU-CTF 2021 Web后四题Writeup
    Vulnhub
    [VNCTF 2021]naive题解
    F5杯 Web部分题目Writeup by atao
    CTFSHOW SSTI 刷题
    C语言文件
    函数+进制转换器
    C语言知识点小结
  • 原文地址:https://www.cnblogs.com/jinpingzhao/p/12772101.html
Copyright © 2011-2022 走看看