🇨🇳
99 的博客
  • 久韭
  • Python
    • 你真的“创建”了类吗?
    • MRO 三定律
    • 描述器学习指南
    • 描述器实现 property
    • 如何做一个好中介
    • PEP 阅读清单
    • Python 双刃剑
    • 类型标注
    • “类”的渐进式剖析
  • Network
    • IPv6
    • 大道至简
    • DNS 根域
    • RFC 阅读清单
    • 基础公共服务
      • DNS
      • NTP
    • MAC 地址厂商信息
    • 点对点的中介
  • Windows
    • Windows 使用小技巧
  • Linux
    • SSH 技高一筹
    • nftables 速成
    • Linux 30 周年
    • 新时代 Linux 命令
    • 树莓派实时性优化
    • Bash DEBUG 一行搞定
  • 佳作收藏
    • 美文
      • 短篇
        • 爱
        • 弟弟
        • 暗途
        • 噩梦
        • 想象
        • 底线
        • 疯人
        • 雪兔
        • 夺妻
        • 闹钟
        • 虐猫
        • 做起来
        • 陈小手
        • 道德极限
        • 符号控制
        • 与人为友
        • 消失的人
        • 时间旅行
        • 情债肉偿
        • 铁血恋爱
        • 太阳黑子
        • 蚂蚁人生
        • 风骚和魅力
        • 我只要一种
        • 不朽的失眠
        • 秋天的怀念
        • 午夜的汽笛
        • 多美的故事
        • 相信不相信
        • 清晨的变故
        • 真实的高贵
        • 神秘领奖人
        • 幸福的夜晚
        • 幸福的生日
        • 我有事找你
        • 我是个窃贼
        • 最担心的是你
        • 客厅里的爆炸
        • 假如是你的话
        • 愿你慢慢长大
        • 民意与伪民意
        • 婚姻中没有天堂
        • 一种深久的不安
        • 非走不可的弯路
        • 单调产生的快乐
        • 我只是讨厌屈服
        • 跳槽只为“软福利”
        • 你的阅读造就了你
        • 聪明人和傻子和奴才
        • 你永远有做不完的事
        • 精神病院里的年轻人
        • 一位短跑运动员的孤独
        • 那些你所不知道的大事
        • 穿过大半个中国去睡你
        • 我觉得自己会永远生猛下去
      • 长篇
        • 早餐
        • 波心
        • 老王
        • 翻浆
        • 小猫
        • 良娼
        • 自信
        • 黑羊
        • 猫人
        • 斜眼
        • 识人
        • 身价
        • 肯肯舞
        • 狗和猫
        • 热包子
        • 黄裙子
        • 老江湖
        • 逃脱术
        • 侯银匠
        • 太原诅咒
        • 死亡花朵
        • 罗马惊艳
        • 刺青时代
        • 好嘴杨巴
        • 扼杀胎儿
        • 纪念照片
        • 紫色人形
        • 天外飞石
        • 戒烟公司
        • 蔡二少爷
        • 女人的星球
        • 一千张糖纸
        • 爱情与投资
        • 赌徒的遗书
        • 飞越流水线
        • 跟踪狂入门
        • 一桩自杀案
        • 机舱里的钟声
        • 桌子还是桌子
        • 一小时的故事
        • 不存在的女友
        • 谁在编造历史
        • 父亲坐在黑暗中
        • 一个小小的建议
        • 彬彬有礼的强盗
        • 18 本画册的爱恋
        • 河流最蓝的地方
        • 好人总会有人疼
        • 偷听谈话的妙趣
        • 公主整夜不能睡
        • 他们那时多有趣
        • 布莱克·沃兹沃斯
        • 坐在路边鼓掌的人
        • 最伟大的科幻小说
        • 你丈夫是干什么的
        • 谁也看不见的阳台
        • 上午打瞌睡的女孩
    • 段子
      • 程序员段子
      • 二次元段子
      • 大老师片段
      • 金句
      • 喝痰
      • 数学家
      • 牛子
      • 男 ♂ 语
      • 甲方乙方
      • 新编故事四则
      • 没人知道大东为何在此舞蹈
  • 日常随记
    • 坑
    • 豆知识
    • 逻辑推断
    • 观影后记
    • LaMDA 有意识吗?
    • VS Code Vim 速记
    • QQ 空间表情符号
    • ZEN of DEBUG
    • 数据收集的途径
    • 呼叫转移设置方式
    • 空中浩劫 ACI 经典
    • 联机海难特色简述
    • 智能家居入门指南
    • 财政学笔记
    • 行为与实验经济学笔记
    • 电商管理学笔记
由 GitBook 提供支持
在本页
  • 引言
  • 0. 粗览官方文档
  • 1. 了解 Python 属性访问顺序
  • 对象属性访问顺序
  • 类属性访问顺序
  • 2. 了解描述器协议
  • 描述器协议
  • 3. 探究描述器核心原理
  • 4. 实例练习
  • 5. 细究官方文档
  • 参考源
在GitHub上编辑
  1. Python

描述器学习指南

从面向过程到面向对象

上一页MRO 三定律下一页描述器实现 property

最后更新于1年前

引言

Python 语言当前使用的解释器主要是 CPython,也就是说,基于面向过程的 C 语言构建了面向对象的 Python,那么其中的基础原理有哪些值得我们学习呢?

描述器

我们来看看官方文档是怎么形容描述器的吧。

学习描述器能更深地理解 Python 工作的原理并更加体会到其设计的优雅性。 描述器是一个强大而通用的协议。 描述器是特征属性、方法静态方法、类方法和 super() 背后的实现机制。 描述器在 Python 内部被广泛使用,实现了自 2.2 版本中(最早由 提出)引入的新式类。 描述器简化了底层的 C 代码并为 Python 的日常程序提供了一组灵活的新工具。

事实上描述器这个主题并不冷门,网上已有了大量的讨论。但是前几天在翻译官方文档间隙查资料的时候,发现已有的博文和参考资料大都比较零散,故在此作以简单整合。

本文的编排顺序是作者精心调整过的,建议您按照标题顺序依次阅读。

作者秉持 KISS 主义,故而本文不对已有的博文做重复陈述,只给出对应链接。

Keep it Simple, Stupid!

0. 粗览官方文档

首先我们当然要 浏览 一下官方文档了,作者已经贡献了简中翻译。

1. 了解 Python 属性访问顺序

首先,面向对象与面向过程的区别之一就是cls.attribute形式的调用,这被称为属性调用,这里的属性是指广义上的,包括基础属性和方法。 那么我们就先来了解一下 Python 中的属性调用的顺序:

对象属性访问顺序

  1. 依照 MRO 顺序的类的类属性中的 数据描述器属性

  2. 实例对象的属性object.__dict__

  3. 依照 MRO 顺序的类的类属性中的 非数据描述器属性

  4. 依照 MRO 顺序的类的类属性中的 普通(非描述器)属性cls.__dict__

类属性访问顺序

  1. 依照元类的 MRO 顺序的类的类属性中的 元类数据描述器属性

  2. 依照 MRO 顺序的类的类属性中的 数据描述器属性

  3. 依照 MRO 顺序的类的类属性中的 普通(非描述器)属性cls.__dict__

  4. 依照 MRO 顺序的类的类属性中的 非数据描述器属性

  5. 依照元类的 MRO 顺序的类的类属性中的 元类非数据描述器属性

Python 中 类的本质是元类创建的对象,所以相当于是外面套了一层不包含普通属性(亦即非描述器属性)的对象属性访问顺序。

2. 了解描述器协议

现在我们可以去看一下描述器的核心内容了。

描述器协议

descr.__get__(self, obj, type=None)

descr.__set__(self, obj, value)

descr.__delete__(self, obj)

定义这些方法中的任何一个的对象被视为描述器,在被作为属性时覆盖其默认行为。

仅当一个包含这些方法的类(称为 描述器类)的实例出现于一个 所有者类 中的时候才会起作用(该描述器必须在所有者类或其某个上级类的字典中)。

如果一个对象定义了 __set__() 或 __delete__(),则它会被视为数据描述器。 仅定义了 __get__() 的描述器称为非数据描述器(它们通常被用于方法,但也可以有其他用途)。

数据和非数据描述器的不同之处在于,如何计算实例字典中条目的替代值。 如果实例的字典具有与数据描述器同名的条目,则数据描述器优先。如果实例的字典具有与非数据描述器同名的条目,则该字典条目优先。

为了使数据描述器成为只读的,应该同时定义 __get__() 和 __set__() ,并在 __set__() 中引发 AttributeError 。用引发异常的占位符定义 __set__() 方法使其成为数据描述器。

3. 探究描述器核心原理

如果想要彻底地理解描述器,那么我们就不得不了解一下描述器的具体代码实现。 但是直接上源码未必太过硬核,以流程图的形式去解析可能是最好的方式,下面这篇文章正是如此。

4. 实例练习

学习了这么多原理,最后自然要来个有实际意义例子来练练手了。看看怎样利用描述器来实现装饰器 property 吧。

5. 细究官方文档

最后我们就可以再回头看看官方文档了,相信这次你可以轻松理解其中内容。

参考源

python 高级编程——描述符 Descriptor 详解(上篇)——python 对象的属性访问优先级与属性的控制与访问)
python 高级编程——描述符 Descriptor 详解(中篇)——python 对象的属性访问优先级与属性的控制与访问)
python 高级编程——描述符 Descriptor 详解(下篇)——python 描述符三剑客详解
描述器 (1)
property 装饰器的描述器实现
【官方文档】描述器使用指南
【官方文档】描述器使用指南
python 高级编程——描述符 Descriptor 详解(上篇)——python 对象的属性访问优先级与属性的控制与访问)
python 高级编程——描述符 Descriptor 详解(中篇)——python 对象的属性访问优先级与属性的控制与访问)
python 高级编程——描述符 Descriptor 详解(下篇)——python 描述符三剑客详解
python 高级编程——描述符 Descriptor 详解(补充篇)——python 描述符实现一些底层高级功能
描述器 (1)
Python 中的类与描述器 (Descriptors)
property 装饰器的描述器实现
PEP252
【官方文档】描述器使用指南
transifex