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 相关文章推荐
使用go和python递归删除.ds store文件的方法
Jan 22 Python
用python实现面向对像的ASP程序实例
Nov 10 Python
Python查找函数f(x)=0根的解决方法
May 07 Python
python3 requests中使用ip代理池随机生成ip的实例
May 07 Python
Python模拟简单电梯调度算法示例
Aug 20 Python
利用django+wechat-python-sdk 创建微信服务器接入的方法
Feb 20 Python
对Pytorch中nn.ModuleList 和 nn.Sequential详解
Aug 18 Python
python实现XML解析的方法解析
Nov 16 Python
opencv3/C++实现视频读取、视频写入
Dec 11 Python
python传到前端的数据,双引号被转义的问题
Apr 03 Python
pip已经安装好第三方库但pycharm中import时还是标红的解决方案
Oct 09 Python
python中判断数字是否为质数的实例讲解
Dec 06 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
多文件上传的例子
2006/10/09 PHP
PHP加速 eAccelerator配置和使用指南
2009/06/05 PHP
PHP 开源框架22个简单简介
2009/08/24 PHP
PHP+JQUERY操作JSON实例
2017/03/23 PHP
PHP支付宝当面付2.0代码
2018/12/21 PHP
laravel 使用事件系统统计浏览量的实现
2019/10/16 PHP
jquery实现拖拽调整Div大小
2015/01/30 Javascript
angularjs学习笔记之完整的项目结构
2015/09/26 Javascript
基于AngularJS+HTML+Groovy实现登录功能
2016/02/17 Javascript
JS hashMap实例详解
2016/05/26 Javascript
jQuery使用EasyUi实现三级联动下拉框效果
2017/03/08 Javascript
浅谈JS中的反柯里化( uncurrying)
2017/08/17 Javascript
利用JS测试目标网站的打开响应速度
2017/12/01 Javascript
详解使用Nuxt.js快速搭建服务端渲染(SSR)应用
2019/03/13 Javascript
vue3.0封装轮播图组件的步骤
2021/03/04 Vue.js
[01:13]2015国际邀请赛线下观战现场
2015/08/08 DOTA
浅谈Django自定义模板标签template_tags的用处
2017/12/20 Python
Python3中正则模块re.compile、re.match及re.search函数用法详解
2018/06/11 Python
Python基于Tkinter模块实现的弹球小游戏
2018/12/27 Python
利用Python对文件夹下图片数据进行批量改名的代码实例
2019/02/21 Python
Python迷宫生成和迷宫破解算法实例
2019/12/24 Python
django 模型中的计算字段实例
2020/05/19 Python
详解python安装matplotlib库三种失败情况
2020/07/28 Python
python sleep和wait对比总结
2021/02/03 Python
Dr. Martens马汀博士官网:马丁靴始祖品牌
2016/10/15 全球购物
纽约通行卡:The New York Pass(免费游览纽约90多个景点)
2017/07/29 全球购物
澳大利亚设计的优质鞋类和适合澳大利亚生活方式的服装:Rivers
2019/04/23 全球购物
安全月宣传标语
2014/10/07 职场文书
借钱欠条怎么写
2015/07/03 职场文书
2019年让高校“心动”的自荐信
2019/03/25 职场文书
教您:房贷工资收入证明应该怎么写?
2019/08/19 职场文书
六年级上册《闻官军收河南河北》的教学设计
2019/11/15 职场文书
三十年再续同学情倡议书
2019/11/27 职场文书
Java中生成微信小程序太阳码的实现方案
2022/06/01 Java/Android
ubuntu开机后ROS程序自启动问题
2022/12/24 Servers
DQL数据查询语句使用示例
2022/12/24 MySQL