Python类型系统

分类

Structural typesNominal types
Runtime checkingDuck typingGoose typing
Static checkingStatic duck typingStatic typing
表1 Python类型系统分类——动态/静态类型检查、显式/隐式声明类间的继承/实现关系

两种结构化类型的形式

本小节讨论表1第一列中的两种类型系统。

首先解释清楚一个概念,协议或者protocol,在Python中,这个概念可以理解为一个方法集合,其中的每个方法都有约定好的签名和语义,但在不同的类型系统下,对于用户自定义类的实现要求是不一样的。

对于Python原生支持的duck typing,程序员可以不必实现协议中的每一个方法,但是只在PEP 544被采纳之后才支持的static duck typing,严格要求实现协议中的每一个方法。在Python社区中,前者称之为动态协议,后者称之为静态协议,如果未明确指明的话,一般指动态协议。

两种形式的共同点是都无需显式声明所实现的协议,会有相对应的方法检查类的方法集合。

Duck typing编程

防御式&Fail Fast

防御式编程的目的是增强程序的安全性,而Fail fast一方面通过尽早抛出异常来避免不可预料的后果,另一方面也便于定位问题,提高升序的可维护性。

那么我们如何发现异常呢?是不是需要程序员一条条编写检查代码呢?答案是否定的,而且用一句话就能解释,EAFP,懂的都懂,不懂的看下面。

EAFP

It’s easier to ask for forgiveness than permission

EAFP带给Python一种很不一样的特质:把思考聚焦在程序的正常执行流上,进而保持思维流的连贯。当然这也得益于Python语言精心设计的Exception类层级。

Goose Typing

Python中没有直接定义Interface这个概念,但是ABC(Abstract Base Class)充当了这一功能,使得程序员可以对现实世界的东西建模,定义语法和语义都严谨的一组方法,然后配合Python自带的isinstanceisubclass函数,可以在运行时灵活地对对象进行自省。

Goose Typing算是对Duck Typing的一种补充,允许适当且适量地使用isinstance,并且第二个参数必须是ABC而不是具体类型。

多继承

菱形继承

在一个菱形的继承关系中,有可能出现命名冲突的问题——互为兄弟节点的两个类各自有自己的方法实现。当出现这种情况时,每种语言都要有一套决议(Resolution)方案,Python的方案为mro,即Method Resolution Order。

mro存储在类的一个名为__mro__的属性中,是一个元组。

super函数

super这个名字可能有些误导,会让人以为会返回当前类的父类。首先先摒弃掉这种望文生义的想法。其次,super的工作机制与mro紧密联系,具体来说,mro决定了在一个多继承关系中类的方法激活顺序,而是否被激活取决于方法的实现是否调用了super。如果调用了super,那么调用链将沿着mro继续;如果没有,调用链就结束。因此,super函数是协作式的。

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *