python的描述符

#描述符是很多高级库,和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件
#描述符分为两种:
#第一种是数据描述符:至少实现了 __get__()和__set__()
#第二种为非数据描述符:没有实现__set__()
#http://www.cnblogs.com/linhaifeng/articles/6204014.html#_label6
#描述符是什么:描述符本质是一个新式类,
# 这个新式类至少实现了__getter__()__set__()__delete__()中的一个,这也被称为描述符
#描述符是干什么的:描述符的作用是用来代理另外一个类的类属性的
# (必须把描述符定义成这个类的类属性,不能定义到构造函数中)
#__get__():调用一个属性时,触发
#__set__():为一个属性赋值时,触发
#__delete__():采用del删除属性时,触发
#直接用描述符本身的对象是没有调用的效果的
class Foo:
    def __get__(self, instance, owner):#取值触发
        print("get")
    def __set__(self, instance, value):#赋值触发
        print("set",instance,value)
        # instance.__dict__["x"]=value #如果进行这步操作 就会在b1中的字典传入值
    def __delete__(self, instance):#删除触发
        print("delete")
f1=Foo()
f1.name='pl'   #调用时候没有触发set 函数  自己用时候不可能执行 必须有另外一个类
print(f1.name)
class Bar:
    x=Foo()  #x被Foo描述 也就是被Foo 所代理了 #在何时 #  定义的是一个类属性 这个属性是Foo 实例化的结果
    def __init__(self,n):
        self.x=n #就类似b1.x=10 #因为有了x=Foo这个属性调用了描述符 所以 触发 如果没有Foo 便会打印自己的
b1=Bar(10)#加入没有Foo找的是自己的属性字典
print(b1.__dict__)
#如果没有被代理的属性 就是自己的
b1.y=1111111111111
print(b1.__dict__)
#自己的字典当中在没有调用描述符时候 便会在自己的函数中执行
#在何地
# f2=Bar()
# f2.x  #调用Foo的实例 一个描述符的对象
# del f2.x   #调用了描述符里的内容
# # print(f2.x)
           #4 注意事项:
# 一 描述符本身应该定义成新式类,被代理的类也应该是新式类
# 二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
# 三 要严格遵循该优先级,优先级由高到底分别是
# 1.类属性
# 2.数据描述符
# 3.实例属性
# 4.非数据描述符
# 5.找不到的属性触发__getattr__()

描述符的优先级:

class Foo:
    def __get__(self, instance, owner):#取值触发
        print("get")
    def __set__(self, instance, value):#赋值触发
        print("set",instance,value)
        # instance.__dict__["x"]=value #如果进行这步操作 就会在下一个类中调用字典传入值
    def __delete__(self, instance):#删除触发
        print("delete")
class Bar:
    x=Foo() #这就显示描述符在何地
b1=Bar()
b1.x=1  #实例化中 会现在自己的属性字典当中寻找 找不到 则在类中找
        # 类对应的是对象,对象里面是一个描述符
print(Bar.x)#触发了get属性
# 没有触发 类属性 会高于 描述符的属性  所以只在自己的字典中触发
del b1.x # 主要先对自己的类实例化 然后去 找描述符
                     #  优先级的大小如下:
                     # 类属性>数据描述符
                     # 数据描述符>实例属性
                     # 实例属性 >非数据描述符
                     # 非数据描述符 >找不到
print("----->"*20)
b2=Bar()
Bar.x=1111111 #当类属性重新对x赋值 便不会触发描述符的操作
b2.x  #这就证明了类属性的优先级高于数据描述符 高于 实例属性

描述符的应用:

#__get__():调用一个属性时,触发
#__set__():为一个属性赋值时,触发
#__delete__():采用del删除属性时,触发
#直接用描述符本身的对象是没有调用的效果的
class Typed:
    def __init__(self,key,expect_type):
        self.key=key
        self.expect_type=expect_type
    def __get__(self, instance, owner):#owner 是p1的类
        print('get方法')
        # print('instance参数【%s】'%instance)
        # print('owner参数【%s】'%owner)
        return instance.__dict__[self.key]  #get方法 会找return 里面的key
    def __set__(self, instance, value):#set里接收的instance 就是p1本身
        print('set方法')
        if not isinstance(value,self.expect_type):
            # print("你传入的类型错误")
            # return #相当于终止函数
            raise TypeError('%s传入的类型错误,不是%s'%(self.key,self.expect_type)) #直接结束
        # print('instance参数【%s】' % instance)
        # print('value参数【%s】'%value )
        instance.__dict__[self.key]=value
    def __delete__(self, instance):
        print("delete方法")

        instance.__dict__.pop(self.key)
        # print('instance参数【%s】' % instance) #p1的实例
class People:
    name=Typed('name',str) #name属性被taped代理了  触发了 t1.__set__
    age=Typed('age',int)
    def __init__(self,name,age,salary):#没有对这些属性加上类型限制
        self.name=name
        self.age=age
        self.salary=salary
p1=People('pl',18,2000000)#实列化的过程  #触发了get 方法
 # 实列属性>非数据描述符  所以不会触发get 函数
print(p1.salary)
print(p1.__dict__)
# #  #加上类型限制
# print("下一步")
# p1.name # 会触发了 get 方法
# # print(p1.name)
# p1.name='egon'#为一个属性赋值时候触发  修改了一下 还是触发了set
# #做了一次属性的更改
# print(p1.__dict__)
# del p1.name #触发了删除的操作
# #数据描述符的优先级高于属性 所以属性的操作都是 去找描述符去了
# print(p1.__dict__)
p1=People(111,18,2000000)
print(p1.__dict__)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值