• python之路(11)描述符


    前言

      描述符是用于代理另一个类的属性,一般用于大型的框架中,在实际的开发项目中较少使用,本质是一个实现了__get__(),__set__(),__delete__()其中一个方法的新式类

      __get__():调用一个属性时执行

      __set__():属性赋值时执行

      __delete__():采用del删除属性时触发

      描述符实现@property

      描述符实现@classmethod

      描述符实现@staticmethod

     示例

    #描述符
    class test:
        def __get__(self, instance, owner):
            print('---get方法')
    
        def __set__(self, instance, value):
            print('---set方法')
    
        def __delete__(self, instance):
            print('---delete方法')
    
    class test2:
        name = test()#描述符代理了test2类里的name属性
    
    t1 = test2()
    #调用了被描述符代理的属性,执行__get__()方法
    t1.name #---get方法
    #赋值了被描述符代理的属性,执行__set__()方法
    t1.name = 1 #---set方法
    #赋值了被描述符代理的属性,执行__delete__()方法
    del t1.name #---delete方法

     属性查找的优先级

      1.类属性

      2.数据描述符(同时实现了__get__()和__set__()方法)

      3.实例属性

      4.非数据描述符(没有实现__set__()方法)

      5.找不到的属性执行__getattr__()

    #非数据描述符
    class test:
        def __get__(self, instance, owner):
            print('get方法')
    
    
    class test2:
        name = test()#描述符代理了test2类里的name属性
    
    t1 = test2()
    #在实例对象里中创建了name属性,并赋值chen
    t1.name = 'chen'
    print(t1.__dict__) #{'name': 'chen'}

    利用描述符实现赋值类型限制(一)

    #数据描述符
    class Typed:
        def __init__(self,key,value_type):
            self.key = key
            self.value_type = value_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.value_type): #判断类型
                raise TypeError('传入的类型不是',self.value_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) #数据描述符代理属性
    
        def __init__(self,name,age):
            self.name = name #赋值操作,执行__set__方法
            self.age = age
    
    
    #测试
    p1 = People('chen',21)
    print(p1.__dict__) #{'name': 'chen', 'age': 21}
    
    p1 = People('chen','21') #报错:TypeError: ('传入的类型不是', <class 'int'>)
    

    利用描述符和装饰器实现赋值类型限制(二)

    #数据描述符
    class Typed:
        def __init__(self,key,value_type):
            self.key = key
            self.value_type = value_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.value_type): #判断类型
                raise TypeError('传入的类型不是',self.value_type)
            instance.__dict__[self.key] = value
    
    
        def __delete__(self, instance):
            print('delete方法')
            instance.__dict__.pop(self.key)
    
    
    #限制赋值类型的装饰器
    def deco(**kwargs):
        def warapper(obj):
            for key,val in kwargs.items():
    
                setattr(obj,key,Typed(key,val)) #在装饰器中给类属性实现描述符代理
    
            return obj
        return warapper
    
    
    @deco(name=str,age=int) #@wrapper ===>People=wrapper(People)
    class People:
        #使用装饰器取代了以下两步
        # name = Typed('name',str) #数据描述符代理属性
        # age = Typed('age',int) #数据描述符代理属性
        def __init__(self,name,age):
            self.name = name #赋值操作,执行__set__方法
            self.age = age
    
    
    #测试
    p1 = People('chen',21)
    '''
    输出:
    set方法
    set方法
    '''
    print(p1.__dict__) #{'name': 'chen', 'age': 21}
    

     描述符实现@property

    class Demoproperty:
        def __init__(self,func):
            print('----+')
            self.func = func
    
    
    class People:
        def __init__(self,name,age):
            self.name = name #赋值操作,执行__set__方法
            self.age = age
    
        @Demoproperty #eat=Demoproperty(eat)
        def eat(self):
            print("%s在吃饭"%self.name)
    
    
    p1 =People('chen',21)
    p1.eat.func(p1) #chen在吃饭
    瞎搞
    #非数据描述符
    class Demoproperty:
        def __init__(self,func):
            self.func = func
    
        def __get__(self, instance, owner):
            print('get')
            res = self.func(instance)
            return res
    
    class People:
        
        def __init__(self,name,age):
            self.name = name #赋值操作,执行__set__方法
            self.age = age
    
        #实现了添加描述符的操作
        @Demoproperty #eat=Demoproperty(eat)
        def eat(self):
            print("%s在吃饭"%self.name)
    
    p1 =People('chen',21)
    p1.eat #chen在吃饭
    

     描述符实现@calssmethod

    classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等  

    class ClassMethod:
        def __init__(self,func):
            self.func=func
        
        def __get__(self, instance, owner): #owner是类
            def feedback(*args,**kwargs):
    
                return self.func(owner,*args,**kwargs)
    
            return feedback #返回一个可以传参的方法
    
    class People:
    
        @ClassMethod # say_hi=ClassMethod(say_hi)
        def say_hi(cls,name,age):
            print('我是%s,年龄%s' %(name,age))
    
    People.say_hi('chen',21) #我是chen,年龄21

    描述符实现@staticmethod

    class StaticMethod:
        def __init__(self,func):
            self.func=func
    
        def __get__(self, instance, owner): #owner是类
            def feedback(*args,**kwargs):
    
                return self.func(*args,**kwargs)
    
            return feedback #返回一个可以传参的方法
    
    class People:
    
        @StaticMethod # say_hi=ClassMethod(say_hi)
        def say_hi(name,age):
            print('我是%s,年龄%s' %(name,age))
    
    People.say_hi('chen',21) #我是chen,年龄21
    

     

  • 相关阅读:
    520了,用32做个简单的小程序
    sql使用手册
    大厂Redis高并发场景设计,面试问的都在这!
    如何根据普通ip地址获取当前地理位置
    理解Python闭包,这应该是最好的例子
    520了,用32做个简单的小程序
    适合 C++ 新手学习的开源项目——在 GitHub 学编程
    寄存器(内存访问)01 零基础入门学习汇编语言13
    寄存器(CPU工作原理)07 零基础入门学习汇编语言12
    数组08 零基础入门学习C语言30
  • 原文地址:https://www.cnblogs.com/shuzhixia/p/10049931.html
Copyright © 2020-2023  润新知