pep 544 Protocols: Structural subtyping (static duck typing)
前言
在 PEP 484 中引入的 Typing hints (类型提示) 可以用来为静态类型检查器和其他第三方工具指定类型元数据。但是在,PEP 484 只指定了名义子类型的语义。在这个 PEP 544 中,指定了协议类的静态和运行时语义,这将为结构性子类型(静态鸭子类型)提供一个支持。
什么是鸭子类型(Duck Typing)?
If it walks like a duck and it quacks like a duck, then it must be a duck。
简单地说,”如果它走路像鸭子,叫起来像鸭子,那它一定是鸭子“。
在编程中这就意味着当我们编写接收特定输入的函数时,我们只需要关心该函数输入的行为、属性,而不是该函数输入的显式类型。
例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为”鸭子”的对象,并调用它的”走”和”叫”方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的”走”和”叫”方法。— 百度百科
那么如何在 Python 中实现“鸭子类型”呢?
鸭子类型
现在有这样子场景,我们需要编写一个函数去计算一个拥有边长(len_side)的物体的周长,伪代码如下:
1 | function calcute_circumference(shape): |
从伪代码不难看出,我们不关心是什么的物体,我们只需要保证这个物体可以有一个 len_side(列表) 字段就可以了。
现在我们可以借由 Protocol
去实现它。
1 | from typing import Protocol |
从上面的例子不难看出 Protocol
有点类似 Java 中的接口,只需要在函数上使用它,并不需要去关注输入的参数的具体类型。
泛型
我们还可以配合使用 typing
中的 TypeVar
实现泛型参数化,让我们的函数更加抽象化,只要符合协议,无论什么类型的输入都可以。
1 | from typing import Protocol |
延伸
上述的例子都可以借由 Python 中的 ABCs 去实现的,但是两者的侧重点有所不同,由于篇幅有限,在下一篇文章,让我们仔细对比一下两者的的区别。