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 Web框架Flask下网站开发入门实例
Feb 08 Python
通过Python爬虫代理IP快速增加博客阅读量
Dec 14 Python
Python和Java进行DES加密和解密的实例
Jan 09 Python
python3写的简单本地文件上传服务器实例
Jun 04 Python
python实现简易数码时钟
Feb 19 Python
用Python和WordCloud绘制词云的实现方法(内附让字体清晰的秘笈)
Jan 08 Python
linux环境中没有网络怎么下载python
Jul 07 Python
Python爬虫学习之获取指定网页源码
Jul 30 Python
python判断自身是否正在运行的方法
Aug 08 Python
win10安装tesserocr配置 Python使用tesserocr识别字母数字验证码
Jan 16 Python
Python实现括号匹配方法详解
Feb 10 Python
详解Django ORM引发的数据库N+1性能问题
Oct 12 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 静态变量与自定义常量的使用方法
2010/01/26 PHP
php中 ob_start等函数截取标准输出的方法
2015/06/22 PHP
Laravel 实现密码重置功能
2018/02/23 PHP
javascript 清除输入框中的数据
2009/04/13 Javascript
setTimeout与setInterval在不同浏览器下的差异
2010/01/24 Javascript
5个最佳的Javascript日期处理类库分享
2012/04/15 Javascript
js简单实现删除记录时的提示效果
2013/12/05 Javascript
使用upstart把nodejs应用封装为系统服务实例
2014/06/01 NodeJs
纯js实现无限空间大小的本地存储
2015/06/18 Javascript
JS实现左右拖动改变内容显示区域大小的方法
2015/10/13 Javascript
VUE JS 使用组件实现双向绑定的示例代码
2017/01/10 Javascript
Java中int与integer的区别(基本数据类型与引用数据类型)
2017/02/19 Javascript
Angular.js实现多个checkbox只能选择一个的方法示例
2017/02/24 Javascript
JS实现微信里判断页面是否被分享成功的方法
2017/06/06 Javascript
nodejs+mongodb aggregate级联查询操作示例
2018/03/17 NodeJs
bootstrap下拉分页样式 带跳转页码
2018/12/29 Javascript
three.js实现炫酷的全景3D重力感应
2018/12/30 Javascript
vue使用el-upload上传文件及Feign服务间传递文件的方法
2019/03/15 Javascript
AutoJs实现刷宝短视频的思路详解
2020/05/22 Javascript
[01:23:59]2018DOTA2亚洲邀请赛 4.1 小组赛 B组 VP vs Secret
2018/04/03 DOTA
[43:03]完美世界DOTA2联赛PWL S2 PXG vs Magma 第二场 11.21
2020/11/24 DOTA
wxPython的安装与使用教程
2018/08/31 Python
python 实现兔子生兔子示例
2019/11/21 Python
python实现小世界网络生成
2019/11/21 Python
matplotlib 画双轴子图无法显示x轴的解决方法
2020/07/27 Python
python获得命令行输入的参数的两种方式
2020/11/02 Python
[原创]赚疯了!转手立赚800+?大佬的python「抢茅台脚本」使用教程
2021/01/12 Python
css3的transform造成z-index无效解决方案
2014/12/04 HTML / CSS
英国领先的大码时装品牌之一:Elvi
2018/08/26 全球购物
2014年采购工作总结
2014/11/20 职场文书
销售合作意向书范本
2015/05/08 职场文书
党小组评议意见
2015/06/02 职场文书
Python自动化测试PO模型封装过程详解
2021/06/22 Python
国庆节到了,利用JS实现一个生成国庆风头像的小工具 详解实现过程
2021/10/05 Javascript
一文搞懂MySQL索引页结构
2022/02/28 MySQL
win10频率超出范围怎么办?win10老显示超出工作频率范围的解决方法
2022/07/07 数码科技