Python的描述符
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的描述符的更多相关文章
- python数据描述符
Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题苦恼的朋友提 ...
- 【python】描述符descriptor
开始看官方文档,各种看不懂,只看到一句Properties, bound and unbound methods, static methods, and class methods are all ...
- python之描述符
描述符是将某种特殊类型的类实例指派给另一个类的属性,某种特殊类型的类就是这个类里面封装了get,set,delete这三个方法,可以将这个类指派给另一个类的某一个属性,这样就可以通过这三个方法对该属性 ...
- python Descriptor (描述符)
简介: python 描述符是新式类(继承自object)中的语言协议,基于描述符可以提供更佳优雅的解决方案. python的classmethod, staticmethod, property都是 ...
- python理解描述符(descriptor)
Descriptor基础 python中的描述符可以用来定义触发自动执行的代码,它像是一个对象属性操作(访问.赋值.删除)的代理类一样.前面介绍过的property是描述符的一种. 大致流程是这样的: ...
- python - 数据描述符(class 内置 get/set/delete方法 )
数据描述符(class 内置 get/set/del方法 ): # 什么是描述符 # 官方的定义:描述符是一种具有“捆绑行为”的对象属性.访问(获取.设置和删除)它的属性时,实际是调用特殊的方法(_g ...
- Python属性描述符(二)
Python存取属性的方式特别不对等,通过实例读取属性时,通常返回的是实例中定义的属性,但如果实例未曾定义过该属性,就会获取类属性,而为实例的属性赋值时,通常会在实例中创建属性,而不会影响到类本身.这 ...
- Python属性描述符(一)
描述符是对多个属性运用相同存取逻辑的一种方式,,是实现了特性协议的类,这个协议包括了__get__.__set__和__delete__方法.property类实现了完整的描述符协议.通常,可以只实现 ...
- Python 属性描述符和属性的查找过程
属性描述符可以用来控制给属性赋值的时候的一些行为 import numbers class IntField: def __get__(self, instance, owner): return s ...
随机推荐
- java nio 读取大文件
package com.yao.bigfile; import java.io.File; import java.io.IOException; import java.io.RandomAcces ...
- (转)Spring+JDBC组合开发
http://blog.csdn.net/yerenyuan_pku/article/details/52882435 搭建和配置Spring与JDBC整合的环境 使用Spring+JDBC集成步骤如 ...
- liunx 中安装mysql 图形界面 phpmyadmin
是浏览器图形界面 1. 安装mysql 图形管理工具. 2. 使用phpmyadmin 图像化工具. 3.下载地址 http://www.phpmyadmin.net/ 4. 查看是否安装这两个包 ...
- docker使用阿里云镜像加速器(属于自己的专属加速器)
https://cr.console.aliyun.com/cn-shanghai/mirrors
- Django的架构
简介 Django继承并简化了MVC架构.MVC中的Controller部分基本全由Django完成.View部分被分割成两部分,即:负责HTML渲染的模板和负责显示逻辑的视图.所以Django又被称 ...
- EEPROM的存储大小
学习单片机时,常见的EEPROM如24C02的大小为2Kbit(有的也称2KB).这里的2KB到底能存储多少数据呢? 2KB中,B表示单位bit,K表示1024. 单片机编程中常用的数据类型为unsi ...
- QTreeWidgetItem封装
#include "qtreewighthelper.h" QTreeWidgetItem* AddQTreeWidgetItemChild(QTreeWidgetItem* pa ...
- CSS中列表项list样式
CSS列表属性 属性 描述 list-style-属性 用于把所有用于列表的属性设置于一个声明中. list-style-image 将图象设置为列表项标志. list-style-position ...
- In line copy and paste to system clipboard
On the Wiki Wiki Activity Random page Videos Photos Chat Community portal To do Contribute Watch ...
- centeros 6 远程升级ssl ssh 的shell脚本
变量说明 SSL_N=openssl-1.0.2p #ssl 版本SSH_N=openssh-7.9p1 #ssh 版本ZLIB_N=zlib-1.2.11 # zlib 版本 脚本分为两个,因为升级 ...