1、描述符的定义

  描述符是与特定属性互相绑定的一种协议,通过方法被触发修改属性,这些方法包括__get__(),__set__(),__delete__().将这些方法定义在类中,即可实现描述符

2、属性与__dict__

  Python中类有属于自己的字典属性,经过类的实例化的对象也同样有自己的字典属性,__dict__

 class Foo(object):
x=10
def f(self):
print('f')
def __init__(self,name,id):
self.name=name
self.id=id
f=Foo('alex','')
print(Foo.__dict__)
print(f.__dict__)
{'__module__': '__main__', 'x': 10, 'f': <function Foo.f at 0x000002677119A950>, '__init__': <function Foo.__init__ at 0x000002677119A840>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
{'name': 'alex', 'id': ''}

  

对象调用属性的方法查找顺序:对象字典,类字典,父类字典,__getattr__方法

3、描述符方法

__set__(self,instance,value)

__get__(self,instance,owner)

 __delete__(self,instance)

    #测试self,instance,value,owner各是何方神圣

 class Foo:
def __set__(self, instance, value):
print('set')
print(self)
print(instance,value)
def __get__(self, instance, owner):
print('get')
print(self)
print(instance,owner)
def __delete__(self, instance):
print('delete')
print(self)
print(instance)
class Test:
x=Foo()
def __init__(self,y):
self.x=y
t=Test(10)
t.x #输出结果
set
<__main__.Foo object at 0x000002D26D10A438>
<__main__.Test object at 0x000002D26D10A470> 10
get
<__main__.Foo object at 0x000002D26D10A438>
<__main__.Test object at 0x000002D26D10A470> <class '__main__.Test'>
 

第15行x=Foo()说明x属性被Foo类所代理一般,涉及对x属性的操作可能会触发Foo类中的三个方法,t为Test实例化的对象,触发构造方法init,执行self.x=y(10),实际类属性与实例新增属性x是井水不犯河水,无相关联,但是类属性x是描述符属性,被Foo代理,python解释器会发现实例字典中的x属性名与类属性同名,类属性(描述符)会优先覆盖。对x的操作交给Foo()代理,触发其中的set函数,打印其中self——类Foo类的信息,instance——被代理的对象信息,value——被代理的值被修改。

第19行对x的属性访问,理所应当,触发其代理的get方法,self——类Foo类的信息,instance——被代理的对象信息,owner——见名知意,被代理属性的最高拥有着,即Test类

其实当一个类中定义了set,get,delete的一个或多个,就可以把这个类称为描述符类。当没有set方法,有其他2个任意或所有时,又被称为非数据描述符。至少有get和set,称为数据描述符

  

4、描述符对象是实例属性

  从上述可知描述符对象是类属性。当描述符对象是实例属性又会怎么样呢?

 class Foo:
def __set__(self, instance, value):
print('set')
print(instance,value)
def __get__(self, instance, owner):
print('get')
print(instance,owner)
def __delete__(self, instance):
print('delete')
print(instance)
class Test:
x=Foo()
def __init__(self):
self.y=Foo()
t=Test()
t.x
t.y
#输出
get
<__main__.Test object at 0x00000175F2FABF28> <class '__main__.Test'>

  咦?为什么只触发了一个get。t.y并没有触发get方法。why???

  因为调用 t.y 时,首先会去调用Test(即Owner)的 __getattribute__() 方法,该方法将 t.y 转化为Test.__dict__['y'].__get__(t, Test), 但是呢,实际上 Test 并没有 y这个属性,y 是属于实例对象的,so,忽略。

5、类描述符对象属性与实例描述符对象属性同名

 class Foo:
def __set__(self, instance, value):
print('set')
print(instance,value)
def __get__(self, instance, owner):
print('get')
print(instance,owner)
def __delete__(self, instance):
print('delete')
print(instance)
class Test:
x=Foo()
def __init__(self):
self.x=Foo()
t=Test()
t.x
-----------------------------------------------------
get
<__main__.Test object at 0x00000246E4ACBF28> <class '__main__.Test'>

大家应该会想,实例属性通过__getattribute__()已经在自己字典中可以找到x,为什么还会触发get方法?

  这涉及到优先级的顺序问题,当解释器发现实例字典中有与描述符属性同名的属性时,描述符优先与实例属性,会覆盖掉实例属性。可以通过类字典验证

 print(Test.__dict__)
-------------
{'__module__': '__main__', 'x': <__main__.Foo object at 0x000002757C138550>, '__init__': <function Test.__init__ at 0x000002757C1DA9D8>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None}

x所对应的value值是其本类对象,而t.__dict__则是个空字典。

6、描述符优先级别顺序

  上面已经提到,当无set方法的描述符称为非数据描述符,有set和get为数据描述符。这2者有啥区别?优先级别的大区别!!!

  类属性>>>数据描述符>>>实例属性>>>>非数据属性>>>>找不到此属性即__getattribute__`  

Python的描述符的更多相关文章

  1. python数据描述符

    Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题苦恼的朋友提 ...

  2. 【python】描述符descriptor

    开始看官方文档,各种看不懂,只看到一句Properties, bound and unbound methods, static methods, and class methods are all ...

  3. python之描述符

    描述符是将某种特殊类型的类实例指派给另一个类的属性,某种特殊类型的类就是这个类里面封装了get,set,delete这三个方法,可以将这个类指派给另一个类的某一个属性,这样就可以通过这三个方法对该属性 ...

  4. python Descriptor (描述符)

    简介: python 描述符是新式类(继承自object)中的语言协议,基于描述符可以提供更佳优雅的解决方案. python的classmethod, staticmethod, property都是 ...

  5. python理解描述符(descriptor)

    Descriptor基础 python中的描述符可以用来定义触发自动执行的代码,它像是一个对象属性操作(访问.赋值.删除)的代理类一样.前面介绍过的property是描述符的一种. 大致流程是这样的: ...

  6. python - 数据描述符(class 内置 get/set/delete方法 )

    数据描述符(class 内置 get/set/del方法 ): # 什么是描述符 # 官方的定义:描述符是一种具有“捆绑行为”的对象属性.访问(获取.设置和删除)它的属性时,实际是调用特殊的方法(_g ...

  7. Python属性描述符(二)

    Python存取属性的方式特别不对等,通过实例读取属性时,通常返回的是实例中定义的属性,但如果实例未曾定义过该属性,就会获取类属性,而为实例的属性赋值时,通常会在实例中创建属性,而不会影响到类本身.这 ...

  8. Python属性描述符(一)

    描述符是对多个属性运用相同存取逻辑的一种方式,,是实现了特性协议的类,这个协议包括了__get__.__set__和__delete__方法.property类实现了完整的描述符协议.通常,可以只实现 ...

  9. Python 属性描述符和属性的查找过程

    属性描述符可以用来控制给属性赋值的时候的一些行为 import numbers class IntField: def __get__(self, instance, owner): return s ...

随机推荐

  1. TFS强制删除离职人员签出锁定项的方法(转)

      项目组一哥们走的时候以独占方式迁出了文件,现在其他人都无法修改,管理员似乎也无法将文件解除.经过摸索,找到了一种暴力的方法——直接改TFS数据库.虽然暴力,却能实实在在地解决这个问题. 步骤: 1 ...

  2. dialog - 从 shell 显示对话框

    总览 (SYNOPSIS) dialog --clear dialog --create-rc file dialog --print-maxsize dialog common-options bo ...

  3. Vue项目结构梳理

    Vue项目结构图: 简单介绍目录结构 build目录是一些webpack的文件,配置参数什么的,一般不用动 config是vue项目的基本配置文件 node_modules是项目中安装的依赖模块 sr ...

  4. 无法读取配置节"system.web.extensions",因为它缺少节声明

    设置 .Net Framework版本 v2.0.50727 要设置成 v4.0.30319

  5. 888. Fair Candy Swap@python

    Alice and Bob have candy bars of different sizes: A[i] is the size of the i-th bar of candy that Ali ...

  6. python UDP-数据报协议

    基于udp协议通信的套接字 服务端 from socket import * server = socket(AF_INET, SOCK_DGRAM) # SOCK_DGRAM=>数据报协议 s ...

  7. Python旅途——数据类型

    1.概要 ​ 今天跟大家分享的是数据类型,数据类型在Python中的重要程度就好比我们汉语中的拼音一样重要. 2.数据类型 1.整形 整形就像是数学中的1.2.3一样,用int来表示. a = 1 # ...

  8. 嵩天老师的零基础Python笔记:https://www.bilibili.com/video/av13570243/?from=search&seid=15873837810484552531 中的15-23讲

    #coding=gbk#嵩天老师的零基础Python笔记:https://www.bilibili.com/video/av13570243/?from=search&seid=1587383 ...

  9. react native 标签出错.

    这种错误为标签错误,没办法,你只能往标签上找了,但不一定是<Text></Text>,我是在<TextInput></TextInput>上出错的,多了 ...

  10. 性能测试工具 - ab 简单应用

    之前知道一般网站性能可以通过 LoadRunner, JMeter, QTP 等相应的软件进行测试, 印象中本科学习 “软件测试” 这门课程时安装并使用过, LoadRunner等不是一个小软件, 安 ...