• 面向对象_描述符


      描述符就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议

    __get__():调用一个属性时触发
    __set__():为一个属性赋值时触发
    __delete__():使用delete删除属性时触发

      描述符的参数

    class Str():
        def __get__(self, instance, owner):
            print('from __get__...')
            print('self',self)        #<__main__.Str object at 0x02D80210>类Str的对象即p1的name属性
            print('instance',instance)#<__main__.People object at 0x02D801D0>类People的对象即p1
            print('owner',owner)      #<class '__main__.People'>类People
    
        def __set__(self, instance, value):
            print('from __set__...')
            print('self',self)        #<__main__.Str object at 0x02D80210>
            print('instance',instance)#<__main__.People object at 0x02D801D0>
            print('value',value)      # lary  p1.name属性的value
    
        def __delete__(self, instance):
            print('from __delete__...')
            print('self',self)        #<__main__.Str object at 0x02D80210>
            print('instance',instance)#<__main__.People object at 0x02D801D0>
    
    class People():
        name = Str()
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
    p1 = People('lary',18)
    p1.name
    del p1.name

    触发

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

    #描述符类产生的实例进行属性操作并不会触发三个方法的执行
    class Foo():
        def __get__(self, instance, owner):
            print('use get')
    
        def __set__(self, instance, value):
            print('use set')
    
        def __delete__(self, instance):
            print('use delete')
    
    f1 = Foo()
    f1.name='lary'
    #描述符代理另外一个类的类属性时才会触发
    
    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类代理
            self.name=name
            self.age=age
    
    p1 = People('lary',18)
    p1.name

    分类

      描述符分为数据描述符和非数据描述符

    #类别一 数据描述符:至少实现了__get__()和__set__()
    class Str:
        def __get__(self, instance, owner):
            print('Str调用')
        def __set__(self, instance, value):
            print('Str设置...')
      
    #类别二 非数据描述符:没有实现__set__()
    class Str:
        def __get__(self, instance, owner):
            print('Str调用')
       

    优先级

      描述符本身应该被定义成新式类,被代理的类也应该是新式类

      必须把描述符定义成这个类的类属性,不能定义到构造函数中

      描述符与类的属性有优先级顺序,必须遵循该优先级

    描述符与类的优先级由高到低
    类属性
    数据描述符
    实例属性
    非数据描述符
    找不到的属性触发__getattr__()
    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
    
    print(People.name)
    People.name = 'lary'
    print('before',People.__dict__)
    print('---')
    del People.name
    print('after',People.__dict__)
    类属性大于数据描述符
    class Str:
        def __get__(self, instance, owner):
            print('Str调用')
        def __set__(self, instance, value):
            print('Str设置...')
        def __delete__(self, instance):
            print('Str删除...')
    
    class Int:
        def __get__(self, instance, owner):
            print('Int调用')
        def __set__(self, instance, value):
            print('Int设置...')
        def __delete__(self, instance):
            print('Int删除...')
    
    class People:
        name=Str()
        age=Int()
        def __init__(self,name,age): #name被Str类代理,age被Int类代理,
            self.name=name
            self.age=age
    
    p1=People('lily',18)
    
    p1.name
    p1.age
    数据描述符大于实例属性
    class Foo:
        def func(self):
            print('我胡汉三又回来了')
    
    f1 = Foo()
    f1.func()                                 #调用类的方法,也可以说是调用非数据描述符,函数是一个非数据描述符对象
    print(dir(Foo.func))
    print(hasattr(Foo.func,'__delete__'))
    print(hasattr(Foo.func,'__set__'))
    print(hasattr(Foo.func,'__get__'))
    
    
    f1.func = '这是实例属性啊'
    print(f1.func)
    
    del f1.func
    
    class Foo:                                #至少实现了__set__和__get__方法的为数据描述符
        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
    
    r1 = Room('厕所',1,1)
    r1.name
    r1.name='厨房'
    
    
    class Foo:
        def __get__(self, instance, owner):   #只实现了__get__方法的为非数据描述符
            print('get')
    class Room:
        name=Foo()
        def __init__(self,name,width,length):
            self.name=name
            self.width=width
            self.length=length
    
    r1 = Room('厕所',1,1)
    print(r1.name)
    r1.name = '厨房'
    print(r1.name)
    实例属性大于非数据描述符
    class Foo(object):
    
        # def __getattribute__(self, item):
        #     print('能不能找到都会来找我', item)
    
        def func(self):
            print('我胡汉三又回来了')
    
    
    f1=Foo()
    # f1.xxxxx
    # f1.func
    print(f1.__dict__)
    f1.func()
    
    
    class animal(object):
    
        def __getattribute__(self, item):
           return object.__getattribute__(self,item)()
    
        def eat(self):
            print('eating...')
    
    #print(animal.__dict__)
    cat = animal()
    #print(cat.__dict__)
    cat.eat
    #当获取属性时,直接return object.__getattribute__(self,*args,**kwargs)
    #如果需要获取某个方法的返回值时,则需要在函数后面加上一个()即可,如果不加的话,返回的是函数引用地址
    #在__getattribute__方法里面,不能用self.xxx这种方式调用。因为调用类的属性每次都会强制调用__getattribute__,所以会导致递归调用
    非数据描述符大于找不到

    使用

    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)
    
    
    class People:
        name=Typed('name',str)
        age=Typed('name',int)
        salary=Typed('name',float)
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
    
    p1=People(123,18,3333.3)
    p1=People('egon','18',3333.3)
    p1=People('egon',18,3333)
    p1=People('egon',18,3333.3)
    数据类型限制

      如果我们的类有很多属性,可以使用类的装饰器来使用描述符

    def decorate(cls):
        print('类的装饰器开始运行啦')
        return cls
    
    @decorate
    class People:
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
    p1 = People('lary',18,4321.3)
    print(p1.name)
    类装饰器:无参
    def typeassert(**kwargs):
        def decorate(cls):
            print('类的装饰器开始运行啦',kwargs)
            return  cls
        return decorate
    @typeassert(name=str,age=int,salary=float)
    class People:
        def __init__(self,name,age,salary):
            self.name=name
            self.age=age
            self.salary=salary
    p1 = People('lary',18,3434.1)
    print(p1.name)
    类装饰器:有参
    #描述符与装饰器的应用
    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)
    class People:
        def __init__(self,name,age,salary):
            self.name = name
            self.age = age
            self.salary = salary
    
    print(People.__dict__)
    p1 = People('lary',18,2343.2)

      自定义属性

    # property
    class Animal():
        def __init__(self,name):
            self.name = name
    
        @property
        def eat(self):
            return self.name
    
    
    animal1 = Animal('cat')
    print(animal1.eat)
    
    
    #自定义property
    #调用传过来的func函数,将对象(instance)作为参数(即类中函数需要的参数self)
    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)
    
    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('lary',1,1)
    print(r1.area)
    自定义property
    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) #计算一次就缓存到实例的属性字典中
                print('第一次访问__get__方法')
                return value
    
    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('lary',1,2)
    print(r1.area) #先从自己的属性字典找,没有再去类的中找,然后触发了area的__get__方法
    print(r1.area) #先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
    
    
    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('第n次访问get方法')
                value = self.func(instance)
                #setattr(instance,self.func.__name__,value) #计算一次就缓存到实例的属性字典中
                instance.__dict__[self.func.__name__]=value
                return value
    
        def __set__(self, instance, value):
            print('hhhhh')
    
    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('lary',1,2)
    print(r1.area)
    print(r1.area)
    print(r1.area)#缓存功能失效每次都去找描述符了.因为描述符实现了set方法,它由非数据描述符变成了数据描述符,数据描述符比实例属性有更高的优先级,因而所有的属性操作都去找描述符了
    实现缓存
    #自定义@classmethod
    
    class Animal():
        feature = 'live'
        def __init__(self,name):
            self.name = name
    
        @classmethod
        def feature_animal(cls):
            return cls.feature
    
    a1 = Animal.feature_animal()
    print(a1)
    
    class lazyClassMethod():
        def __init__(self,func):
            self.func = func
    
        def __get__(self, instance, owner):
            def feedback():
                print('在这里可以加功能哦')
                return self.func(owner)
            return feedback
    
    
    class Animal():
        feature = 'live'
    
        def __init__(self,name):
            self.name = name
    
        @lazyClassMethod
        def feature_animal(cls):
            return cls.feature
    
    a1 = Animal('cat')
    res=a1.feature_animal()
    print(res)
    
    #带参数的自定义@classmethod
    class lazyClassMethod():
        def __init__(self,func):
            self.func = func
    
        def __get__(self, instance, owner):
            def feedback(*args,**kwargs):
                print('在这里可以加功能哦')
                return self.func(owner,*args,**kwargs)
            return feedback
    
    
    class Animal():
        feature = 'live'
    
        def __init__(self,name):
            self.name = name
    
        @lazyClassMethod
        def feature_animal(cls,msg):
            print('animal is %s:%s'%(cls.feature,msg))
    
    a1 = Animal('cat')
    res=a1.feature_animal('so cute')
    自定义classmethod
    #自定义staticmethod
    
    class Animal():
    
        @staticmethod
        def eat(food,water):
            print('animal is eating %s drink %s'%(food,water))
    
    a1 = Animal()
    a1.eat('meat','water')
    
    class lazyStaticmethod():
        def __init__(self,func):
            self.func = func
    
        def __get__(self, instance, owner):
            def feedback(*args,**kwargs):
                return self.func(*args,**kwargs)
            return feedback
    
    
    class Animal():
    
        @lazyStaticmethod    #eat = lazyStaticmethod(eat)
        def eat(food,water):
            print('animal is eating %s drink %s'%(food,water))
    
    a1 = Animal()
    a1.eat('food','water')
    自定义staticmethod
  • 相关阅读:
    培训界最大的互联网企业【推荐】
    十类经典office实用技巧
    十类经典office实用技巧
    十类经典office实用技巧
    【★】电子产品降价的3大原因!
    【★】电子产品降价的3大原因!
    【★】电子产品降价的3大原因!
    ★会用这两键,你就是电脑高手了
    ★会用这两键,你就是电脑高手了
    ★会用这两键,你就是电脑高手了
  • 原文地址:https://www.cnblogs.com/iamluoli/p/9885128.html
Copyright © 2020-2023  润新知