描述器实现 property

描述器实战应用

引言

在 Python 官方文档中的 描述器使用指南 一篇中,给出了常用装饰器 property 的 Python 代码模拟实现,且这个实现是基于描述器原理的。在本文中,作者将利用这段代码,向你展示 描述器的实际运行原理

装饰器基本内容

首先我们回忆一下装饰器的有关内容。

装饰器本质是个返回函数的函数,表现为数学概念中的复合函数(gf)(x)g(f(x))\big(g \circ f\big)(x) \Rightarrow g\big(f(x)\big)

下面我们用伪代码再补充一些容易产生疑问的情况。

多层装饰器的含义

@dec2
@dec1
def func(arg1, arg2, ...):
    pass

↑↑↑ 等价于 ↓↓↓

func = dec2(dec1(func))

带参装饰器的含义

@decomaker(argA, argB, ...)
def func(arg1, arg2, ...):
    pass

↑↑↑ 等价于 ↓↓↓

类装饰器和函数装饰器是一致的,只相当于将 func 代表的函数换做 cls 代表的类罢了,故这里不再多做涉及。

如果对于装饰器还有问题的话建议阅读一下官方 PEP,可以直接使用 Google 翻译成中文,可读性还是可以接受的。

PEP 318 -- Decorators for Functions and Methods PEP 3129 – Class Decorators

描述器基本内容

这里推荐我针对描述器撰写的上一篇博文

描述器学习指南

官方模拟的源码

我们首先看一下用描述器模拟实现装饰器 property 的源代码。

(这里大概看一下就好,我们后文再详细分析)

代码分析

改写测试用代码

其实作者比较喜欢的方式是利用 VS Code 在代码段顶部就加上断点,然后逐句执行查看代码的具体运行位置和变量值。 但这种方式难以通过文字向大家展示,所以我换了个变通的方式,在每个关键环节都加一个 print() 输出相关内容,这样我们看代码的命令行反馈就可以了。

更改后的测试代码如下:

全部输出

运行以上代码得到的输出是:

由于这其中涉及的内容较多,我们拆开来做分析。

初始化部分

对象 a1 创建及属性操作部分

对象 a2 创建及属性操作部分

@property 中的小陷阱

扩展内容

其实在同一篇中官方也给出了 staticmethodclassmethod 的类似模拟实现,有兴趣的读者也不妨一览:

参考

最后更新于