zoukankan      html  css  js  c++  java
  • python(描述符应用与类的装饰器)

    __enter__和__exit__

    数据描述符:至少实现__get__,__set__方法的

    非数据描述符:没有__set__方法的

    上下文管理协议(with语句)改写,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。

    # -*- coding: utf-8 -*-
    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('b.txt') as f:
        print('=====>执行代码块')
        # print(f,f.name)
    # -*- coding: utf-8 -*-
    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('with中代码块执行完毕时执行我啊')
            #下面三个ext执行完毕就代表with代码块里的语句执行完毕,出现异常,下面的代码不再执行
            print(exc_type) #异常类型
            print(exc_val)  #异常值
            print(exc_tb)   #追溯信息
    
    with Open('b.txt') as f:    #触发__enter__
        print('=====>执行代码块')
        raise AttributeError('***着火啦,救火啊***')
    print('0'*100)      #------->不会执行
    

    用途:

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

    2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制

    描述符应用

    控制输入类型

    # -*- coding: utf-8 -*-
    class Typed:
        def __init__(self,key):
            self.key=key
    
        def __get__(self,instance,owner):
            print('get方法')
            # print('isinstance参数;',isinstance)
            # print('owner参数;',owner)
            return instance.__dict__[self.key]
    
        def __set__(self,instance,value):
            print('set方法')
            # print('isinstance参数;',instance)
            # print('owner参数;',value)
            #通过初始化函数写活了
            if not isinstance(value,str):
                print('输入不是字符串')
            else:
                instance.__dict__[self.key]=value
    
        def __delete__(self,instance):
                print('delete方法')
                # print('isinstance参数;', instance)
                instance.__dict__.pop(self.key)
    
    
    class people:
        name=Typed('name')
        # age=Typed('age')
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
    
    p1=people("bob",22,5000)
    p1.name
    print(p1.__dict__)  #没有name属性,他被数据描述符代理了
    del p1.name
    print(p1.__dict__)
    p2=people(1,22,5000)
    

    进一步改进

    # -*- coding: utf-8 -*-
    class Typed:
        def __init__(self,key,expected_type):
            self.key=key
            self.expected_type=expected_type
    
        def __get__(self,instance,owner):
            # print('get方法')
            # print('isinstance参数;',isinstance)
            # print('owner参数;',owner)
            return instance.__dict__[self.key]
    
        def __set__(self,instance,value):
            # print('set方法')
            # print('isinstance参数;',instance)
            # print('owner参数;',value)
            #通过初始化函数写活了
            if not isinstance(value,self.expected_type):
                print('输入不是%s'%self.expected_type)
            else:
                instance.__dict__[self.key]=value
    
        def __delete__(self,instance):
                print('delete方法')
                # print('isinstance参数;', instance)
                instance.__dict__.pop(self.key)
    
    
    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
    
    p1=people("bob",22,5000.0)
    p1.name
    print(p1.__dict__)  #没有name属性,他被数据描述符代理了
    del p1.name
    print(p1.__dict__)
    p2=people(1,22,5000.0)
    

     类的装饰器

    初级(没有参数):

    # -*- coding: utf-8 -*-
    def decorate(cls):
        print('类的装饰器开始运行啦------>')
        return cls
    
    @decorate       #无参:People=decorate(People)
    class People:
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
            print(self.age,self.name,self.salary)
    
    p1=People('egon',18,3333.3)    

    ------------恢复内容开始------------

    __enter__和__exit__

    数据描述符:至少实现__get__,__set__方法的

    非数据描述符:没有__set__方法的

    上下文管理协议(with语句)改写,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。

    # -*- coding: utf-8 -*-
    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('b.txt') as f:
        print('=====>执行代码块')
        # print(f,f.name)
    # -*- coding: utf-8 -*-
    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('with中代码块执行完毕时执行我啊')
            #下面三个ext执行完毕就代表with代码块里的语句执行完毕,出现异常,下面的代码不再执行
            print(exc_type) #异常类型
            print(exc_val)  #异常值
            print(exc_tb)   #追溯信息
    
    with Open('b.txt') as f:    #触发__enter__
        print('=====>执行代码块')
        raise AttributeError('***着火啦,救火啊***')
    print('0'*100)      #------->不会执行
    

    用途:

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

    2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制

    描述符应用

    控制输入类型

    # -*- coding: utf-8 -*-
    class Typed:
        def __init__(self,key):
            self.key=key
    
        def __get__(self,instance,owner):
            print('get方法')
            # print('isinstance参数;',isinstance)
            # print('owner参数;',owner)
            return instance.__dict__[self.key]
    
        def __set__(self,instance,value):
            print('set方法')
            # print('isinstance参数;',instance)
            # print('owner参数;',value)
            #通过初始化函数写活了
            if not isinstance(value,str):
                print('输入不是字符串')
            else:
                instance.__dict__[self.key]=value
    
        def __delete__(self,instance):
                print('delete方法')
                # print('isinstance参数;', instance)
                instance.__dict__.pop(self.key)
    
    
    class people:
        name=Typed('name')
        # age=Typed('age')
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
    
    p1=people("bob",22,5000)
    p1.name
    print(p1.__dict__)  #没有name属性,他被数据描述符代理了
    del p1.name
    print(p1.__dict__)
    p2=people(1,22,5000)
    

    进一步改进

    # -*- coding: utf-8 -*-
    class Typed:
        def __init__(self,key,expected_type):
            self.key=key
            self.expected_type=expected_type
    
        def __get__(self,instance,owner):
            # print('get方法')
            # print('isinstance参数;',isinstance)
            # print('owner参数;',owner)
            return instance.__dict__[self.key]
    
        def __set__(self,instance,value):
            # print('set方法')
            # print('isinstance参数;',instance)
            # print('owner参数;',value)
            #通过初始化函数写活了
            if not isinstance(value,self.expected_type):
                print('输入不是%s'%self.expected_type)
            else:
                instance.__dict__[self.key]=value
    
        def __delete__(self,instance):
                print('delete方法')
                # print('isinstance参数;', instance)
                instance.__dict__.pop(self.key)
    
    
    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
    
    p1=people("bob",22,5000.0)
    p1.name
    print(p1.__dict__)  #没有name属性,他被数据描述符代理了
    del p1.name
    print(p1.__dict__)
    p2=people(1,22,5000.0)
    

     类的装饰器

    初级(没有参数):

    # -*- coding: utf-8 -*-
    def decorate(cls):
        print('类的装饰器开始运行啦------>')
        return cls
    
    @decorate       #无参:People=decorate(People)
    class People:
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
            print(self.age,self.name,self.salary)
    
    p1=People('egon',18,3333.3)    

    ------------恢复内容开始------------

    __enter__和__exit__

    数据描述符:至少实现__get__,__set__方法的

    非数据描述符:没有__set__方法的

    上下文管理协议(with语句)改写,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。

    # -*- coding: utf-8 -*-
    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('b.txt') as f:
        print('=====>执行代码块')
        # print(f,f.name)
    # -*- coding: utf-8 -*-
    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('with中代码块执行完毕时执行我啊')
            #下面三个ext执行完毕就代表with代码块里的语句执行完毕,出现异常,下面的代码不再执行
            print(exc_type) #异常类型
            print(exc_val)  #异常值
            print(exc_tb)   #追溯信息
    
    with Open('b.txt') as f:    #触发__enter__
        print('=====>执行代码块')
        raise AttributeError('***着火啦,救火啊***')
    print('0'*100)      #------->不会执行
    

    用途:

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

    2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制

    描述符应用

    控制输入类型

    # -*- coding: utf-8 -*-
    class Typed:
        def __init__(self,key):
            self.key=key
    
        def __get__(self,instance,owner):
            print('get方法')
            # print('isinstance参数;',isinstance)
            # print('owner参数;',owner)
            return instance.__dict__[self.key]
    
        def __set__(self,instance,value):
            print('set方法')
            # print('isinstance参数;',instance)
            # print('owner参数;',value)
            #通过初始化函数写活了
            if not isinstance(value,str):
                print('输入不是字符串')
            else:
                instance.__dict__[self.key]=value
    
        def __delete__(self,instance):
                print('delete方法')
                # print('isinstance参数;', instance)
                instance.__dict__.pop(self.key)
    
    
    class people:
        name=Typed('name')
        # age=Typed('age')
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
    
    p1=people("bob",22,5000)
    p1.name
    print(p1.__dict__)  #没有name属性,他被数据描述符代理了
    del p1.name
    print(p1.__dict__)
    p2=people(1,22,5000)
    

    进一步改进

    # -*- coding: utf-8 -*-
    class Typed:
        def __init__(self,key,expected_type):
            self.key=key
            self.expected_type=expected_type
    
        def __get__(self,instance,owner):
            # print('get方法')
            # print('isinstance参数;',isinstance)
            # print('owner参数;',owner)
            return instance.__dict__[self.key]
    
        def __set__(self,instance,value):
            # print('set方法')
            # print('isinstance参数;',instance)
            # print('owner参数;',value)
            #通过初始化函数写活了
            if not isinstance(value,self.expected_type):
                print('输入不是%s'%self.expected_type)
            else:
                instance.__dict__[self.key]=value
    
        def __delete__(self,instance):
                print('delete方法')
                # print('isinstance参数;', instance)
                instance.__dict__.pop(self.key)
    
    
    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
    
    p1=people("bob",22,5000.0)
    p1.name
    print(p1.__dict__)  #没有name属性,他被数据描述符代理了
    del p1.name
    print(p1.__dict__)
    p2=people(1,22,5000.0)
    

     类的装饰器

    初级(没有参数):

    # -*- coding: utf-8 -*-
    def decorate(cls):
        print('类的装饰器开始运行啦------>')
        return cls
    
    @decorate       #无参:People=decorate(People)
    class People:
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
            print(self.age,self.name,self.salary)
    
    p1=People('egon',18,3333.3)    

    进阶(有参数)

    # -*- coding: utf-8 -*-
    def typeassert(**kwargs):
    
        def decorate(cls):
            print('2------>')
            for key,value in kwargs.items():
                setattr(cls,key,value)
            return cls
        print('1------>', kwargs)
        return decorate
    @typeassert()   #name=str,age=int,salary=float
    #有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
    class People:
        pass
        # def __init__(self,name,age,salary):
        #     self.name=name
        #     self.age=age
        #     self.salary=salary
    
    print(People.__dict__)
    
    @typeassert(hobby='ball')
    class bar():
        pass
    #添加了hobby属性 print(bar.__dict__)

     可添加不定个数属性的示例:

    # -*- coding: utf-8 -*-
    class Typed:
        def __init__(self,name,expected_type):
            self.name=name
            self.expected_type=expected_type
        def __get__(self, instance, owner):
            print('get--->',instance,owner)
            if instance is None:
                return self
            return instance.__dict__[self.name]
    
        def __set__(self, instance, value):
            print('set--->',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):
            print('delete--->',instance)
            instance.__dict__.pop(self.name)
    
    def typeassert(**kwargs):
        def decorate(cls):
            print('类的装饰器开始运行啦------>',kwargs)
            for name,expected_type in kwargs.items():
                setattr(cls,name,Typed(name,expected_type))
            return cls
        return decorate
    
    @typeassert(name=str,age=int,salary=float)#在此添加要增加的属性
    #有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
    class People:
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
    
    print(People.__dict__)
    p1=People('egon',18,3333.3)  

    自定制property

    装饰器可以是函数,也可以是类类型。

    # -*- coding: utf-8 -*-
    class Lazyproperty:
        def __init__(self,func):
            self.func=func
        def __get__(self, instance, owner):
            print('这是我们自己定制的静态属性,r1.area实际是要执行r1.area()')
            if instance is None:
                return self
            return self.func(instance) #此时你应该明白,到底是谁在为你做自动传递self的事情
    
    class Room:
        def __init__(self,name,width,length):
            self.name=name
            self.width=width
            self.length=length
    
        @Lazyproperty #area=Lazyproperty(area) 相当于定义了一个类属性,即描述符
        def area(self):
            return self.width * self.length
    
    r1=Room('alex',1,1)
    print(r1.area)      #将r1.area传参数写在Lazyproperty中的__get__里

     应用:自制property实现延迟计算功能

    # -*- coding: utf-8 -*-
    class Lazyproperty:
        def __init__(self,func):
            self.func=func
        def __get__(self, instance, owner):
            print('这是我们自己定制的静态属性,r1.area实际是要执行r1.area()')
            if instance is None:
                return self
            else:
                print('--->')
                value=self.func(instance)
                setattr(instance,self.func.__name__,value) #计算一次就缓存到实例的属性字典中
                return value
        # 如果加了set,将该非数据描述符变为数据描述符,优先级高于实列属性,缓存能力丧失
        # def __set__(self, instance, value):
        #     print('hahahahahah')
    
    class Room:
        def __init__(self,name,width,length):
            self.name=name
            self.width=width
            self.length=length
    
        @Lazyproperty #area=Lazyproperty(area) 相当于'定义了一个类属性,即描述符'
        def area(self):
            return self.width * self.length
    
    r1=Room('alex',1,1)
    print(r1.area) #先从自己的属性字典找,没有再去类的中找,然后出发了area的__get__方法
    print(r1.area) #先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
    

    property补充:一个静态属性property本质就是实现了get,set,delete三种方法

    # -*- coding: utf-8 -*-
    class Foo:
        @property
        def AAA(self):
            print('get的时候运行我啊')
    
        @AAA.setter
        def AAA(self,value):
            print('set的时候运行我啊')
    
        @AAA.deleter
        def AAA(self):
            print('delete的时候运行我啊')
    
    #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
    del f1.AAA
    

    应用(类型检测)

    # -*- coding: utf-8 -*-
    class People:
        def __init__(self,name):
            self.name=name #实例化就触发property
    
        @property
        def name(self):
            # return self.name #无限递归
            print('get------>')
            return self.DouNiWan
    
        @name.setter
        def name(self,value):
            print('set------>')
            if not isinstance(value,str):
                raise TypeError('必须是字符串类型')
            self.DouNiWan=value
    
        @name.deleter
        def name(self):
            print('delete------>')
            del self.DouNiWan
    
    p1=People('alex') #self.name实际是存放到self.DouNiWan里
    print(p1.name)
    
    print(p1.__dict__)
    p1.name=1

     元类

    所有定义的类都是由type产生的。

    # -*- coding: utf-8 -*-
    class foo:
        pass
    print(type(foo))
    

    定义类的两种方法

    # -*- coding: utf-8 -*-
    class foo:
        pass
    print(type(foo))
    print(foo)
    
    def __init__(self,name,age):
        self.name=name
        self.age=age
    
    def test(self):
        print('=======>')
    Foo=type('foo1',(object,),{'x':1,'__init__':__init__,'test':test})
    print(Foo)
    print(Foo.__dict__)
    foo_1=Foo('alex',22)
    foo_1.test()
    

    自定义元类(详情查看连接)

  • 相关阅读:
    Linux中的中断处理
    Yocto使用小技巧
    udev学习笔记汇总
    USB gadget学习笔记
    Linux常用命令
    Linux下软件安装方法
    278. First Bad Version
    MySQL的索引
    7. Reverse Integer
    排序算法
  • 原文地址:https://www.cnblogs.com/2018-1025/p/12399387.html
Copyright © 2011-2022 走看看