• Python基础第21天


    一:描述符

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

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

    class Foo:
        def __get__(self, instance, owner):
            print('get方法')
        def __set__(self, instance, value):
            print('set方法')
            instance.__dict__['x']=value  #b1.__dict__
        def __delete__(self, instance):
            print('delete方法')

    何时何地用 :

       描述符应该在另外一个类的类属性定义,请看例子

    class Foo:
        def __get__(self, instance, owner):
            print('get方法')
        def __set__(self, instance, value):
            print('set方法')
            # instance.__dict__['x']=value  #b1.__dict__
        def __delete__(self, instance):
            print('delete方法')
    
    
    # f1=Foo()
    # f1.name='egon'#自己不会触发
    #
    class Bar:
        x=Foo()   #在何地    这就是描述符,x被Foo描述
        def __init__(self,x):
            self.x=x
    print(Bar.__dict__)
    #在何时
    b1=Bar(10)
    b1.x
    b1.x=1
    del b1.x
    print(b1.__dict__) #所以是空

    描述符分类:

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

    描述符优先级高低分别是:

    1.类属性
    2.数据描述符
    3.实例属性
    4.非数据描述符
    5.找不到的属性触发__getattr__()

    class Foo:
        def __get__(self, instance, owner):
            print('get方法')
        def __set__(self, instance, value):
            print('set方法')
            instance.__dict__['x']=value  #b1.__dict__
        def __delete__(self, instance):
            print('delete方法')
    
    class Bar:
        x=Foo()
    
    print(Bar.x)  #get方法没有返回值
    Bar.x=1
    print(Bar.__dict__)
    print(Bar.x)  #不会触发get方法,所以类属性比数据描述符有更高优先级
    
    print(Bar.__dict__)
    b1=Bar()   #实例化
    b1.x #get
    b1.x=1  #set
    del b1.x  #delete   说明数据描述符比实例属性有更高的优先级
    #
    b1=Bar()
    Bar.x=11111111111111111
    b1.x  #不会触发
    1/2/3之间的优先级级比较
    class Foo:
        def __get__(self, instance, owner):
            print('get方法')
        # def __delete__(self, instance):
        #     print('delete方法')
    
    
    class Bar:
        x=Foo()
    
    b1=Bar()
    b1.x=1
    print(b1.__dict__)  #{'x': 1}  说明实例属性比非数据描述符优先级高
    实例属性>非数据描述符
    class Foo:
        def __get__(self, instance, owner):
            print('get方法')
        # def __delete__(self, instance):
        #     print('delete方法')
    class Bar:
        x=Foo()
    
    b1=Bar()
    b1.x=1
    print(b1.__dict__)  #{'x': 1}  说明实例属性比非数据描述符优先级高
    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='厨房'
    print(r1.name)   #None
    
    
    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='厨房'
    print(r1.name)   #厨房
    数据描述符>实例属性>非数据描述符

    二:__enter__  和__exit__

    操作文件对象的时候可以这么写:

    with open(a.txt) as f:

         '代码块'

    上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法

    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
            # return self
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('with中代码块执行完毕时执行我啊')
    
    
    with Open('a.txt') as f:
        print('=====>执行代码块')
        # print(f,f.name)
    
    上下文管理协议:enter会在with执行后触发,而exit会在with里面代码块执行完毕触发。

    总结:

    优点:

    1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预

    2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处

    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('执行enter')
            return self
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('执行exit')
            print(exc_type)
            print(exc_val)  #异常的值
            print(exc_tb)   #追踪异常的类 traceback
            return True   # with语句执行完 因为返回True,结束with后接着往下走
    with Open('a.txt') as f:  #触发enter ,其返回值self给f  结束后会触发exit   f=obj.__enter__()
        print('=====>')
        print(f)
        print(asdfghjkl)  #没有直接报错,一旦有异常直接跳到exit
        print('---------------')
    print('0000000000000000')
  • 相关阅读:
    【LibreOJ】#6257. 「CodePlus 2017 12 月赛」可做题2
    【Atcoer】ARC088 E
    【Atcoder】ARC088 D
    【CodeForces】671 D. Roads in Yusland
    【CodeForces】671 B. Robin Hood
    【CodeForces】671 C. Ultimate Weirdness of an Array
    【CodeForces】679 A. Bear and Prime 100
    【CodeForces】679 B. Bear and Tower of Cubes
    【BZOJ】3262: 陌上花开
    【CodeForces】899 F. Letters Removing
  • 原文地址:https://www.cnblogs.com/xyd134/p/6561978.html
Copyright © 2020-2023  润新知