Python描述符descriptor使用原理解析


Posted in Python onMarch 21, 2020

描述符(descriptor)是实现了__get__、__set__、__del__方法的类,进一步可以细分为两类:

数据描述符:实现了__get__和__set__

非数据描述符:没有实现__set__

描述符在类的属性调用中起着很重要的作用,类在调用属性时,遵守两个规则:

按照实例属性、类属性的顺序选择属性,即实例属性优先于类属性

如果在类属性中发现同名的数据描述符,那么该描述符会优先于实例属性

非数据描述符会被实例属性覆盖

class A:
  def __get__(self, obj, cls):
    return f"{obj}: get"
class B:
  value = A()

  def __init__(self):
    self.value = 4
def main():
  g = B()
  print(g.value)
  print(g.__dict__)
if __name__ == "__main__":
  main()

输出结果

4
{'value': 4}

数据描述符优于实例属性

class A:
  def __get__(self, obj, cls):
    return f"{obj}: get"

  def __set__(self, obj, value):
    print(f"{obj}: set, {value}")

class B:
  value = A()

  def __init__(self):
    self.value = 4

def main():
  g = B()
  print(g.value)
  print(g.__dict__)

if __name__ == "__main__":
  main()

输出结果

<__main__.B object at 0x000001165EB85898>: set, 4
<__main__.B object at 0x000001165EB85898>: get
{}

从上述两个例子中可以看到,类B的value属性是一个描述符,当value属性是一个数据描述符时,它屏蔽了实例的同名属性value,实例对value属性的读取与赋值都会直接被转移到类属性value上。

使用描述符实现类的静态方法与类方法

from functools import partial

class Staticmethod:

  def __init__(self, method):
    self.method = method

  def __get__(self, obj, cls):
    return self.method

class Classmethod:

  def __init__(self, method):
    self.method = method
  
  def __get__(self, obj, cls):
    return partial(self.method, cls)

class A:

  @Staticmethod
  def f(self):
    print(f"I'm method f, the value is {self}")
  
  @Classmethod
  def c(self):
    print(f"my class is {self}")
a = A()
a.f(23)
A.f(23)
a.c()
A.c()

输出结果

I'm method f, the value is 23
I'm method f, the value is 23
my class is <class '__main__.A'>
my class is <class '__main__.A'>

静态方法与类方法统一了类属性的两种引用方式。这种统一的过程可以使用描述符修改属性访问的默认方式实现。静态方法限制实例的默认绑定,将方法当做普通函数使用;类方法始终将类作为第一个参数传入,上述的partial将类固定为方法的第一个参数。

总结

  • 描述符是实现了__get__、__set__、__del__等特殊方法的类,在属性访问时起着很大的作用。
  • 数据描述符会覆盖同名的实例属性,通过使用数据描述符,达到通过实例修改类变量的目的。
  • 描述符用于修改属性的默认访问方式,借此可以实现类方法与静态方法。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
学习python (1)
Oct 31 Python
python监控文件并且发送告警邮件
Jun 21 Python
python实现归并排序算法
Nov 22 Python
python中调试或排错的五种方法示例
Sep 12 Python
Python实现大数据收集至excel的思路详解
Jan 03 Python
Python3 操作 MySQL 插入一条数据并返回主键 id的实例
Mar 02 Python
Python中remove漏删和索引越界问题的解决
Mar 18 Python
python 给图像添加透明度(alpha通道)
Apr 09 Python
Python几种常见算法汇总
Jun 02 Python
如何基于python把文字图片写入word文档
Jul 31 Python
OpenCV-Python实现人脸磨皮算法
Jun 07 Python
Python语言中的数据类型-序列
Feb 24 Python
Python如何省略括号方法详解
Mar 21 #Python
Python如何使用bokeh包和geojson数据绘制地图
Mar 21 #Python
Spring Boot中使用IntelliJ IDEA插件EasyCode一键生成代码详细方法
Mar 20 #Python
python+opencv实现移动侦测(帧差法)
Mar 20 #Python
Java Spring项目国际化(i18n)详细方法与实例
Mar 20 #Python
Python 自由定制表格的实现示例
Mar 20 #Python
python实现opencv+scoket网络实时图传
Mar 20 #Python
You might like
PHP模块 Memcached功能多于Memcache
2011/06/14 PHP
php addslashes 利用递归实现使用反斜线引用字符串
2013/08/05 PHP
PHP错误和异长常处理总结
2014/03/06 PHP
PhpDocumentor 2安装以及生成API文档的方法
2014/05/21 PHP
php中字符查找函数strpos、strrchr与strpbrk用法
2014/11/18 PHP
PHP使用xmllint命令处理xml与html的方法
2014/12/15 PHP
php支付宝系列之电脑网站支付
2018/05/30 PHP
PHP中检查isset()和!empty()函数的必要性
2019/02/13 PHP
PHP配置ZendOpcache插件加速
2019/02/14 PHP
newxtree.js代码
2007/03/13 Javascript
基于JQuery的列表拖动排序实现代码
2013/10/01 Javascript
PHP和NodeJs开发的应用如何共用Session
2015/04/16 NodeJs
基于vue的下拉刷新指令和滚动刷新指令
2016/12/23 Javascript
实例详解display:none与visible:hidden的区别
2017/03/30 Javascript
vue.js项目 el-input 组件 监听回车键实现搜索功能示例
2018/08/25 Javascript
Nodejs使用Mongodb存储与提供后端CRD服务详解
2018/09/04 NodeJs
微信小程序云开发实现数据添加、查询和分页
2019/05/17 Javascript
AngularJs的$http发送POST请求,php无法接收Post的数据问题及解决方案
2020/08/13 Javascript
[01:03:03]VP vs Mineski 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
python对于requests的封装方法详解
2019/01/03 Python
PyCharm在新窗口打开项目的方法
2019/01/17 Python
python 模拟贷款卡号生成规则过程解析
2019/08/30 Python
python数据库编程 Mysql实现通讯录
2020/03/27 Python
从0到1使用python开发一个半自动答题小程序的实现
2020/05/12 Python
Python常见反爬虫机制解决方案
2020/06/01 Python
python:HDF和CSV存储优劣对比分析
2020/06/08 Python
查看keras的默认backend实现方式
2020/06/19 Python
车库门开启器、遥控器和零件:Chamberlain
2019/04/09 全球购物
小学综治宣传月活动总结
2014/07/02 职场文书
入党积极分子自我批评思想汇报
2014/10/10 职场文书
2014年财政局工作总结
2014/12/09 职场文书
公务员个人年终总结
2015/02/12 职场文书
2015年纪念“卢沟桥事变”78周年活动方案
2015/05/06 职场文书
Java spring单点登录系统
2021/09/04 Java/Android
Mysql数据库表中为什么有索引却没有提高查询速度
2022/02/24 MySQL
MySql数据库 查询时间序列间隔
2022/05/11 MySQL