Python descriptor(描述符)的实现

本文详细介绍了Python中的描述符,包括描述符的作用、如何实现以及在类型检查、创建只读属性和避免实例属性冲突中的应用。描述符是Python中用于自定义属性访问的重要机制,涉及到__get__, __set__, __delete__等方法。通过描述符,可以实现数据描述符和非数据描述符,以及数据和非数据描述符的区别。文章还讨论了描述符的调用机制、陷阱以及在类层次和实例层次上的不同行为。此外,还提到了如何通过数据字典法和标签法解决实例间数据独立的问题,并给出了描述符在回调、类型检查和设置只读属性等方面的应用。" 111324450,10292896,变频空调保护代码解析与维修指南,"['空调技术', '故障诊断', '传感器应用', '变频技术', '家电维修']
摘要由CSDN通过智能技术生成

问题

问题1

Python是一种动态语言,不支持类型检查。当需要对一个对象执行类型检查时,可能会采用下面的方式:


    class Foo(object):
     def __init__(self,a):
     if isinstance(a,int):
      self.__a = a
     else:
      raise TypeError("Must be an int")
    
     def set_a(self,val):
     if isinstance(val,int):
      self.__a = val
     else:
      raise TypeError("Must be an int")
    
     def get_a(self):
     return self.__a

上述是一种类型检查的方法,但是如果需要类型检查的参数非常多的话就会变得非常繁琐,重复代码太多,Python这么简洁,优雅,肯定有更好的解决方法。另外上述方法也有缺陷。


    f = Foo(1)
    print f.get_a() #1
    print f._Foo__a #1,还是能访问到= =
    f._Foo__a = 'test'
    print f.get_a() #test,还是改变了__a的值,而且不是int型
    print f._Foo__a #test

问题2

在一个对象中,创建一个只读属性。

问题3


    class Foo(object):
     a = 1
    f = Foo()
    print f.a #1,实例属性中没有a属性,所以到Foo.__dict__中查找
    print Foo.a #1
    print f.__dict__ #{}
    f.a = 2  #增加一个名为a的实例属性
    print f.a #2,搜索属性时先在实例字典中查找,然后再去类的字典中查找,在实例的__dict__中找到了..
    print Foo.a #1
    print f.__dict__ #{'a': 2}

如果不想给实例 f 增加实例属性,而是想对类属性操作怎么办呢。解决方案:

  1. 使用 class.attr 改变值;

Foo.a = 2 就不会给实例增加实例属性了。

  1. 自定义属性访问,描述符;

    class descriptor(object):
     def __init__(self,val):
     self.val = val
     def __get__(self,obj,type = None):
     print 'get',
     return self.val
     def __set__(self,obj,val):
     print 'set',val
     self.val = val
     def __delete__(self,obj):
     raise AttributeError("Can't delete attribute")
    class Foo(object):
     a = descriptor(0)
    
    f = Foo()
    print f.a #get 0
    print Foo.a #get 0
    print f.__dict__ #{}
    f.a = 2  #set 2,并没有增加实例属性
    print f.a #get 2
    print Foo.a #get 2
    print f.__dict__ #{}

问题总结

上述三个问题均与属性访问有关,如果能够自定义属性访问,上述问题就能解决啦= =。其实问题3已经给出了解决方法,就是描述符…

描述符的定义和介绍

​ 描述符(Descriptor)是Python中非常重要的一部分,它广泛应用于Python的内核。

​ 一般来说,描述符就是一个带有绑定方法的对象,只不过照比其他对象多了几个特殊的描述符方法,即 __get__() , __set__()
, __delete__()对描述符对象的属性访问主要通过描述符方法。

**定义:一个对象如果定义了__get__() , __set__() , __delete__()
方法中的任何一个,它就可以被称为描述符。 **

​ 对属性的访问 默认 是从对象的字典中获取(get),设置(set)和删除(delete)属性。

假设有实例a,a有属性x,获取a.x的值。

一般来说, a.x 会按以下顺序查找属性,查找链: a.__dict__['x']type(a).__dict__['x']根据mro顺序在type(a)的父类中查找(不包括元类)

​ 但是, 如果被查找的属性是一个描述符,并且为类属性,那么就会覆盖其默认行为,转而去调用描述符方法。注意,描述符仅适用于新式类和新式对象。


    class descriptor(object):
     def __init__(self,val):
      self.val = val
    
     def __get__(self, obj, objtype):
      print 'get',
      return self.val
    
     def __set__(self, obj, val):
      print 'set'
      self.val = val
    
    class Foo(object):
     x = descriptor(0)
     y = 0
    
    f = Foo()
    '''描述符覆盖默认的访问行为'''
    print f.x   #get 0,调用的是描述符的__get__函数
    print f.__dict__ #{}
    f.x = 1    #set,调用的是描述符的__set__函数
    print f.x   #get 1
    print f.__dict__ #{},即使赋值也没有增加实例属性...,是不是覆盖了默认行为- -
    f.y = 2    
    print f.__dict__ #{'y': 2},因为没有与y同名的描述符对象...

**描述符十分强大。properties , methods , static methods , class methods , and super() 都是基于描述符实现的。 **
从Python2.2开始,描述符就在新式类中出现了。描述符是一个灵活的工具,使程序开发更加便利。感觉描述符很吊啊…

Descriptor Protocol(描述符协议)

descriptor.__get__(self, obj, type=None) --> value

descriptor.__set__(self, obj, value) --> None

descriptor.__delete__(self, obj) --> None

上述三个方法就是描述符方法,如果一个对象定义了描述符方法中的任何一个,那么这个对象就会成为描述符。

假设有一个对象t,t.a是一个定义了三个描述符方法的描述符,并且a是类属性,调用情况如下:

print t.a → a.__get__(t, type(t))

t.a = v → a.__se

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值