博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面向对象_描述符
阅读量:7228 次
发布时间:2019-06-29

本文共 11758 字,大约阅读时间需要 39 分钟。

  描述符就是一个新式类,在这个新式类中,至少实现了__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)      #
类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 = agep1 = People('lary',18)p1.namedel 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=agep1 = 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=ageprint(People.name)People.name = 'lary'print('before',People.__dict__)print('---')del People.nameprint('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=agep1=People('lily',18)p1.namep1.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.funcclass 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=lengthr1 = Room('厕所',1,1)r1.namer1.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=lengthr1 = 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.funcprint(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=salaryp1=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@decorateclass People:    def __init__(self,name,age,salary):        self.name=name        self.age=age        self.salary=salaryp1 = 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=salaryp1 = 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 = salaryprint(People.__dict__)p1 = People('lary',18,2343.2)

  自定义属性

# propertyclass Animal():    def __init__(self,name):        self.name = name    @property    def eat(self):        return self.nameanimal1 = 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.lengthr1 = 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 valueclass 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.lengthr1 = 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.lengthr1 = Room('lary',1,2)print(r1.area)print(r1.area)print(r1.area)#缓存功能失效每次都去找描述符了.因为描述符实现了set方法,它由非数据描述符变成了数据描述符,数据描述符比实例属性有更高的优先级,因而所有的属性操作都去找描述符了
实现缓存
#自定义@classmethodclass Animal():    feature = 'live'    def __init__(self,name):        self.name = name    @classmethod    def feature_animal(cls):        return cls.featurea1 = 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 feedbackclass Animal():    feature = 'live'    def __init__(self,name):        self.name = name    @lazyClassMethod    def feature_animal(cls):        return cls.featurea1 = Animal('cat')res=a1.feature_animal()print(res)#带参数的自定义@classmethodclass 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 feedbackclass 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
#自定义staticmethodclass 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 feedbackclass 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

 

转载于:https://www.cnblogs.com/iamluoli/p/9885128.html

你可能感兴趣的文章
2019年最火热的Golang项目
查看>>
可实现RSSD云硬盘120万IOPS的SPDK IO路径优化实践
查看>>
Vue项目部署遇到的坑(你肯定会遇到!)
查看>>
资源分享计划第三期 0511
查看>>
awk 文本处理
查看>>
【JSConf EU 2018】主题总结 (部分主题已有中文文章)
查看>>
JavaScript面向对象名词详解
查看>>
Java设计模式学习 - 责任链模式
查看>>
JVM,DVM,ART
查看>>
webgl滤镜--会呼吸的痛
查看>>
用Go语言实现微信支付SDK
查看>>
oauth2在php实践
查看>>
LeetCode.914 卡牌分组
查看>>
填坑app:compileDebugJavaWithJavac
查看>>
Android 100+行实现本地跳一跳辅助(不需要连接电脑)
查看>>
位状态的使用
查看>>
面试技术题笔记
查看>>
Myth源码解析系列之一-项目简介
查看>>
JS易混淆的方法整理
查看>>
iOS下JS与OC互相调用(八)--Cordova详解+实战
查看>>