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脚本判断 Linux 是否运行在虚拟机上
Apr 25 Python
Python设置在shell脚本中自动补全功能的方法
Jun 25 Python
对python中的乘法dot和对应分量相乘multiply详解
Nov 14 Python
Python异步操作MySQL示例【使用aiomysql】
May 16 Python
Python re 模块findall() 函数返回值展现方式解析
Aug 09 Python
Python编程快速上手——Excel到CSV的转换程序案例分析
Feb 28 Python
django 模版关闭转义方式
May 14 Python
Python多线程正确用法实例解析
May 30 Python
关于Kotlin中SAM转换的那些事
Sep 15 Python
python查询MySQL将数据写入Excel
Oct 29 Python
Numpy中np.max的用法及np.maximum区别
Nov 27 Python
python开发人人对战的五子棋小游戏
May 02 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 网页过期时间的控制代码
2009/06/29 PHP
PHP中session变量的销毁
2014/02/27 PHP
PHP制作百度词典查词采集器
2015/01/29 PHP
php判断表是否存在的方法
2015/06/18 PHP
在WordPress中使用wp-cron插件来设置定时任务
2015/12/10 PHP
Linux环境下php实现给网站截图的方法
2016/05/03 PHP
基于PHP实现用户注册登录功能
2016/10/14 PHP
PHP mysqli事务操作常用方法分析
2017/07/22 PHP
thinkPHP3.2使用RBAC实现权限管理的实现
2019/08/27 PHP
锋利的jQuery 要点归纳(一) jQuery选择器
2010/03/21 Javascript
初学js 新节点的创建 删除 的步骤
2011/07/04 Javascript
怎么通过onclick事件获取js函数返回值(代码少)
2015/07/28 Javascript
JS动态日期时间的获取方法
2015/09/28 Javascript
原生javascript实现addClass,removeClass,hasClass函数
2016/02/25 Javascript
jQuery插件formValidator实现表单验证
2016/05/23 Javascript
详细探究ES6之Proxy代理
2016/07/22 Javascript
AngularJS实现数据列表的增加、删除和上移下移等功能实例
2016/09/05 Javascript
jquery事件绑定解绑机制源码解析
2016/09/19 Javascript
Vue.js学习示例分享
2017/02/05 Javascript
nodejs模块学习之connect解析
2017/07/05 NodeJs
node使用UEditor富文本编辑器的方法实例
2017/07/11 Javascript
浅谈关于vue中scss公用的解决方案
2019/12/02 Javascript
基于vue实现微博三方登录流程解析
2020/11/04 Javascript
精确查找PHP WEBSHELL木马的方法(1)
2011/04/12 Python
Python中除法使用的注意事项
2014/08/21 Python
Python深入学习之内存管理
2014/08/31 Python
Python实现的ini文件操作类分享
2014/11/20 Python
利用Python中的mock库对Python代码进行模拟测试
2015/04/16 Python
详细解析Python当中的数据类型和变量
2015/04/25 Python
使用Python创建简单的HTTP服务器的方法步骤
2019/04/26 Python
Pycharm内置终端及远程SSH工具的使用教程图文详解
2020/03/19 Python
怀旧收藏品和经典纪念品:Betty’s Attic
2018/08/29 全球购物
Web Service面试题:如何搭建Axis2的开发环境
2012/06/20 面试题
Delphi软件工程师试题
2013/01/29 面试题
医学院护理专业应届生求职信
2013/11/12 职场文书
茶叶生产计划书
2014/01/10 职场文书