• python之描述符应用与类的装饰器


    一、描述符应用

    1.1上下文管理协议

    在上文中我们提到with语句中的上下文管理器。with语句可以如此简单但强大,主要依赖于上下文管理器。那么什么是上下文管理器?上下文管理器就是实现了上下文协议的类,而上下文协议就是一个类要实现__enter__()和__exit__()两个方法。一个类只要实现了__enter__()和__exit__(),我们就称之为上下文管理器下面我们具体说下这两个方法。

    __enter__():主要执行一些环境准备工作,同时返回一资源对象。如果上下文管理器open("test.txt")的__enter__()函数返回一个文件对象。

    __exit__():完整形式为__exit__(type, value, traceback),这三个参数和调用sys.exec_info()函数返回值是一样的,分别为异常类型、异常信息和堆栈。如果执行体语句没有引发异常,则这三个参数均被设为None。否则,它们将包含上下文的异常信息。__exit_()方法返回True或False,分别指示被引发的异常有没有被处理,如果返回False,引发的异常将会被传递出上下文。如果__exit__()函数内部引发了异常,则会覆盖掉执行体的中引发的异常。处理异常时,不需要重新抛出异常,只需要返回False,with语句会检测__exit__()返回False来处理异常。

    如果我们要自定义一个上下文管理器,只需要定义一个类并且是实现__enter__()和__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)
            return True           # exit里面吞噬了异常
    
    with Open('a.txt') as f:      #触发enter
        print(f)
        print(adcasd)            #异常触发exit
        print(f.name)            # 执行完后触发exit
    print('1234')
    View Code

    with的应用:

    with obj as f:
        '代码块‘
        
    1 with obj ------>>触发obj.__enter__(),拿到返回值
    
    2 as f -------->>f=返回值
    
    3 with obj as f 等同于    f=obj.__enter__()
    
    4 执行代码块
    一:没有异常的情况下,整个代码块运行完毕后去触发__exit__,它的三个参数都为None
    二:有异常的情况下,从异常的位置直接触发__exit__
      a:如果的__exit__返回值为True,代表吞噬了异常
      b:如果的__exit__返回值不为True,代表吐出了异常
      c: __exit__的运行完毕就代表了整个with语句的执行完毕

    1.2描述符的应用
    描述符协议都是针对对象属性的访问。先要明白我们不会去针对一个全局的def使用property进行装饰。我们一般都是在类里面使用。可以对类的访问使用描述符(比较少用),更常用的是针对类实例的访问使用描述符协议。

    class Typed:
        def __init__(self,key,expect_type):
            self.key=key
            self.expect_type=expect_type
    
        def __get__(self, instance, owner):
            print('执行get方法')
            return instance.__dict__[self.key]
    
        def __set__(self, instance, value):
            print('执行set方法')
            if not isinstance(value,self.expect_type):
                # print('传给的不是字符串,错误')
                # return
                raise TypeError('%s传给的不是%s' %(self.key,self.expect_type))
            instance.__dict__[self.key]=value
    
        def __delete__(self, instance):
            print('执行delete方法')
            instance.__dict__.pop(self.key)
    
    class People:
        name=Typed('name',str)
        age=Typed('age',int)      #age是数字
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
    
    # p1=People('czd',22,12345)
    
    p1=People('czd',22,12345)
    
    p1.age
    print(p1.age)
    View Code

    1.3描述符的自定制property

    class Lazyproperty:
        def __init__(self,func):
            self.func=func
        def __get__(self, instance, owner):
            print('get')
            print('instance')
            print('owner')
            res=self.func(instance)
            return res
    class Room:
        def __init__(self,name,width,length):
            self.name=name
            self.width=width
            self.length=length
    
        # @property    #area=property(area)
        @Lazyproperty   #area=Lazyproperty(area)
        def area(self):
            return self.width * self.length
        @property
        def test(self):
            return '123'
    
    r1=Room('厕所',3,2)
    print(r1.area)
    
    # print(Room.__dict__)
    print(r1.test)
    print(Room.test)
    View Code

    二、类的装饰器

    2.1简单的类的装饰器

    def deco(func):
        print('-------->')
        return func
    
    # @deco      #test=deco(test)
    # def test():
    #     print('test函数运行')
    # test()
    
    @deco   #Foo=deco(Foo)
    class Foo:
        pass
    
    f1=Foo()
    print(f1)
    View Code

    2.2类的装饰器加强版

    def Typed(**kwargs):
        def deco(obj):
            for key,val in kwargs.items():
                setattr(obj,key,val)
            return obj
        return deco
    
    @Typed(x=1,y=1,z=3)    #1.Typed(x=1,y=2,z=3) ------>deco  2.@deco------>Foo=deco(Foo)
    class Foo:
        pass
    print(Foo.__dict__)
    
    @Typed(name='czd')
    class Bar:
        pass
    print(Bar.name)
    View Code

    2.3类的装饰器应用

    class Typed:
        def __init__(self,key,expect_type):
            self.key=key
            self.expect_type=expect_type
    
        def __get__(self, instance, owner):
            print('执行get方法')
            return instance.__dict__[self.key]
    
        def __set__(self, instance, value):
            print('执行set方法')
            if not isinstance(value,self.expect_type):
                # print('传给的不是字符串,错误')
                # return
                raise TypeError('%s传给的不是%s' %(self.key,self.expect_type))
            instance.__dict__[self.key]=value
    
        def __delete__(self, instance):
            print('执行delete方法')
            instance.__dict__.pop(self.key)
    
    def deco(**kwargs):
        def wrapper(obj):
            for key,val in kwargs.items():
    
                setattr(obj,key,Typed(key,val))
                # setattr(People,'name',Typed('name',str))    #People.name=Typed('name',str)
            return obj
        return wrapper
    
    @deco(name=str,age=int,salary=float,gender=str)
    class People:
        def __init__(self,name,age,salary,gender):
            self.name=name
            self.age=age
            self.salary=salary
            self.gender=gender
    
    p1=People('czd',22,12345.8,'male')
    print(People.__dict__)
    View Code

    三、元类

    3.1元类的介绍

    class Foo:
        pass
    print(Foo)
    print(Foo.__dict__)
    
    
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def test(self):
        print('----->')
    FFo=type('FFo',(object,),{'x':1,'__init__':__init__,'test':test})
    print(FFo)
    print(FFo.__dict__)
    
    f1=FFo('czd',23)
    print(f1.name)
    f1.test()
    View Code

    3.2自定制元类

    class Mytype(type):
        def __init__(self,a,b,c):
            print('元类的构造函数执行')
            print(a)
            print(b)
            print(c)
        def __call__(self, *args, **kwargs):
            print('------>')
            print(self)
            print(args,kwargs)
            obj=object.__new__(self)   #------>f1
            self.__init__(obj,*args,**kwargs)
            return obj
    
    class Foo(metaclass=Mytype):     #Mytype(4个参数)-----》__init__ --------->(self,'Foo',(),{})
        def __init__(self,name):     #f1.name=name
            self.name=name
    
    # f1=Foo('name')
    # print(Foo)
    f1=Foo('czd')
    print(f1.__dict__)
    print(f1)
    View Code
  • 相关阅读:
    JAVA基础集合(二)
    JAVA基础XML的解析
    JAVA基础集合(一)
    JAVA基础网络编程
    JAVA基础File类
    JAVA基础IO流(二)
    JAVA基础JDBC二(常用的开源工具)
    JAVA基础异常
    JAVA基础JDBC(一)
    JAVA基础反射
  • 原文地址:https://www.cnblogs.com/changzhendong/p/11336641.html
Copyright © 2020-2023  润新知