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实现检测服务器是否可以ping通的2种方法
Jan 01 Python
python根据出生日期获得年龄的方法
Mar 31 Python
Python批量合并有合并单元格的Excel文件详解
Apr 05 Python
对pandas中to_dict的用法详解
Jun 05 Python
浅谈Python中函数的定义及其调用方法
Jul 19 Python
python经典趣味24点游戏程序设计
Jul 26 Python
python并发编程多进程之守护进程原理解析
Aug 20 Python
pyqt5 QlistView列表显示的实现示例
Mar 24 Python
Python SMTP发送电子邮件的示例
Sep 23 Python
删除pycharm鼠标右键快捷键打开项目的操作
Jan 16 Python
解决tensorflow模型压缩的问题_踩坑无数,总算搞定
Mar 02 Python
Github 使用python对copilot做些简单使用测试
Apr 14 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
PHP4之真OO
2006/10/09 PHP
php根据年月获取季度的方法
2014/03/31 PHP
CodeIgniter框架URL路由总结
2014/09/03 PHP
php获取网页里所有图片并存入数组的方法
2015/04/06 PHP
PHP+Mysql无刷新问答评论系统(源码)
2016/12/20 PHP
PHP写的简单数字验证码实例
2017/05/23 PHP
php进行md5加密简单实例方法
2019/09/19 PHP
Laravel5.1框架路由分组用法实例分析
2020/01/04 PHP
jQuery 性能优化指南(3)
2009/05/21 Javascript
JavaScript和ActionScript的交互实现代码
2010/08/01 Javascript
JSON无限折叠菜单编写实例
2013/12/16 Javascript
javascript基本类型详解
2014/11/28 Javascript
浅析AngularJS Filter用法
2015/12/28 Javascript
javascript运算符——逻辑运算符全面解析
2016/06/27 Javascript
js获取腾讯视频ID的方法
2016/10/03 Javascript
js时间控件只显示年月
2017/01/08 Javascript
Angular2使用Augury来调试Angular2程序
2017/05/21 Javascript
JS+php后台实现文件上传功能详解
2019/03/02 Javascript
layui实现数据分页功能(ajax异步)
2019/07/27 Javascript
在vue中把含有html标签转为html渲染页面的实例
2019/10/28 Javascript
[01:25]DOTA2自定义游戏灵园鬼域等你踏足
2015/10/30 DOTA
python中self原理实例分析
2015/04/30 Python
Python出现segfault错误解决方法
2016/04/16 Python
基于python时间处理方法(详解)
2017/08/14 Python
python多进程实现进程间通信实例
2017/11/24 Python
Python打印“菱形”星号代码方法
2018/02/05 Python
python实现弹窗祝福效果
2019/04/07 Python
Python PyInstaller库基本使用方法分析
2019/12/12 Python
英国的一家创新礼品和小工具零售商:Menkind
2019/08/24 全球购物
项目负责人任命书
2014/06/04 职场文书
推广普通话共筑中国梦演讲稿
2014/09/21 职场文书
企业2014年度工作总结
2014/12/10 职场文书
2015年质量管理工作总结范文
2015/05/18 职场文书
一篇文章弄懂MySQL查询语句的执行过程
2021/05/07 MySQL
Nginx反向代理至go-fastdfs案例讲解
2021/08/02 Servers
进阶篇之linux环境下安装MySQL数据库
2022/04/09 MySQL