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的函数的一些高阶特性
Apr 27 Python
python中的代码编码格式转换问题
Jun 10 Python
Python调用系统底层API播放wav文件的方法
Aug 11 Python
Python 获得命令行参数的方法(推荐)
Jan 24 Python
Flask之请求钩子的实现
Dec 23 Python
在Python运行时动态查看进程内部信息的方法
Feb 22 Python
Python3+Appium实现多台移动设备操作的方法
Jul 05 Python
python3读取csv文件任意行列代码实例
Jan 13 Python
Python第三方包之DingDingBot钉钉机器人
Apr 09 Python
python搜索算法原理及实例讲解
Nov 18 Python
Python环境配置实现pip加速过程解析
Nov 27 Python
pytorch锁死在dataloader(训练时卡死)
May 28 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更新mysql后获取影响的行数发生异常解决方法
2013/03/28 PHP
php预定义变量使用帮助(带实例)
2013/10/30 PHP
php命名空间学习详解
2014/02/27 PHP
Windows下的PHP安装pear教程
2014/10/24 PHP
PHP类相关知识点实例总结
2016/09/28 PHP
Referer原理与图片防盗链实现方法详解
2019/07/03 PHP
jQuery 使用手册(六)
2009/09/23 Javascript
jquery load()在firefox(火狐)下显示不正常的解决方法
2011/04/05 Javascript
multiSteps 基于Jquery的多步骤滑动切换插件
2011/07/22 Javascript
JQuery扩展插件Validate—6 radio、checkbox、select的验证
2011/09/05 Javascript
javascript实现禁止鼠标滚轮事件
2015/07/24 Javascript
JavaScript获取页面中超链接数量的方法
2015/11/09 Javascript
Google 地图获取API Key详细教程
2016/08/06 Javascript
bootstrapValidator bootstrap-select验证不可用的解决办法
2017/01/11 Javascript
JS实现求数组起始项到终止项之和的方法【基于数组扩展函数】
2017/06/13 Javascript
基于JavaScript中标识符的命名规则介绍
2018/01/06 Javascript
vue-cli2.0转3.0之项目搭建的详细步骤
2018/12/11 Javascript
使用 Vue cli 3.0 构建自定义组件库的方法
2019/04/30 Javascript
ES6的解构赋值实例详解
2019/05/06 Javascript
微信小程序生成海报分享朋友圈的实现方法
2019/05/06 Javascript
vue调用本地摄像头实现拍照功能
2020/08/14 Javascript
js仿淘宝放大镜效果
2020/12/28 Javascript
[46:04]Liquid vs VP Supermajor决赛 BO 第四场 6.10
2018/07/05 DOTA
Python数据分析中Groupby用法之通过字典或Series进行分组的实例
2017/12/08 Python
python实现n个数中选出m个数的方法
2018/11/13 Python
python实现名片管理系统
2018/11/29 Python
python shell命令行中import多层目录下的模块操作
2020/03/09 Python
python使用matplotlib的savefig保存时图片保存不完整的问题
2021/01/08 Python
驾驶员安全责任书
2014/07/22 职场文书
合作意向书
2014/07/30 职场文书
2014年团委工作总结
2014/11/13 职场文书
导游欢迎词范文
2015/01/23 职场文书
监考失职检讨书
2015/01/26 职场文书
会计求职信怎么写
2015/03/20 职场文书
解决Pytorch中关于model.eval的问题
2021/05/22 Python
Python实现byte转integer
2021/06/03 Python