79、Python之鸭子类型:没有听过鸭子类型?关键在于认知的转变

南宫理的日志录 2024-11-06 10:06:38
引言

不同于Java等静态类型的语言,Python基于动态类型系统的设计理念,使得Python在很多应用场景中,显得更急灵活、高效。而在动态类型系统中,有一个很重要的概念,就是“鸭子类型”。鸭子类型的背后,代表的是一些编程认知方式的转变,是对“协议”、“行为”与类型之间关系的更加深入的理解。

本文的主要内容有:

1、什么是鸭子类型

2、简单对比Python与Java的类型系统

3、鸭子类型的应用

4、鸭子类型的注意事项

什么是鸭子类型

所谓“鸭子类型(Duck Typing)”,是一种动态类型系统的编程概念。其核心思想来自于詹姆斯·惠特科姆·莱利的鸭子测试:“如果它走起来像鸭子,叫起来像鸭子,那么它就是鸭子”。

换句话说,在鸭子类型中,对象的有效性不依赖于其显式的类型,而是依赖于对象是否具有所需要的属性和方法。

可以粗略的理解为,所谓的实体的强类型,更像是一种标签。而我们在实际业务场景中,需要的是某些能力、行为。所以,只要某个实体对象,具备了我们所需要的能力,能够在系统交互中实现所需要的行为,那么至于这个实体对象被标记为什么类型,其实并不是很重要。

以“捉老鼠”的场景为例,我们最根本的诉求是不被老鼠所影响,想到的方法,或者需要具备的能力是“能够把老鼠捉起来”。至于是白猫、黑猫、多管闲事的狗,又或者是有些屠龙技的人,只要能达到捉到老鼠的目的即可。

所以,本质上来说,在动态类型系统中,我们所关注的不再是静态类型系统中,一个实体对象所属的类型,而是这个实体对象所具备的属性和方法。而所应该具备的属性和方法,更加抽象来说,叫做“协议”。所以,我们的关注视角,从具体类型转换到了协议。能理解了这一个认知的转换,就已经理解了鸭子类型的本质。

简单对比Python与Java的类型系统

如果有同学比较熟悉Java,应该能够深刻地感受到,在Java的编程世界中,类型系统是静态的,类型检查是在编译时进行的,并且对象的类型是显式声明的。这样的好处在于,有些错误可以在编译期就能提早发现。但是,也会导致更多的强制类型转换、一大堆样板代码等。

在Java中,如果我们定义不同动物,定义一个函数接收具体的动物对象,发出不同的叫声,我们大概需要这样做:

需要先有一个表示动物的类型,可以是一个接口或者抽象类,用于指向具体的动物子类型的对象。

定义对象,还要明知道类型,再手动显式声明类型。

运行结果:

这是一套标准的面向对象的继承的设计实现,也确实达到了我们想要的效果。

在Python中,我们也可以通过面向对象的继承的思路,来实现同样的效果。但是,由于Python是动态类型的,我们还可以有更简化的实现方式:

从代码行数的角度,依然能看到更加简洁。

从设计实现上,Dog和Duck两个类型没有任何继承关系(当然都是object类的子类,这点这里可以忽略)。它们定义了同样的方法bark(),所以在进行函数make_sound()调用时,只要传入的对象实例具有bark()方法,就能成功执行。

执行结果:

从上面的对比可以看出,Python中,类型的检查是运行时进行的,类型是隐式的。Python中的鸭子类型的存在,允许我们更加专注于对象的行为,而非其必须是某个特定类型,或者繁琐地进行类型继承关系的设计。

鸭子类型的应用

1、编程的灵活性和多态性

鸭子类型的引入,首先给我们提供了一种新的“多态”的思路,我们不需要进行类的继承体系的设计,不需要考虑抽象出具有特定功能的公共父类,只需要定义同样的行为方法即可。这种实现多态的方式,似乎是一种更加自然的方式。

2、代码的简洁性

鸭子类型减少了类型检查和类型转换的需求,从而使得代码更加简洁易读。在Java中,通常需要通过强制转换来实现多态行为。而在Python中,这些都变得不是必要的。

3、兼容性和扩展性

鸭子类型使得代码更加具有兼容性和可扩展性。之所以这样说,是因为,我们可以随时定义新的对象类型,只要定义特定的方法,就可以将新的类型的对象,传递给一个现有的函数。这样,使得对现有功能的扩展变得更加灵活、方便。

鸭子类型的注意事项

需要说明的是,虽然鸭子类型是我们接下来几篇文章的主角,但是还是有一些潜在的需要注意的事项:

1、运行时错误

由于类型检查被推迟到了运行时进行,所以,有些错误只有在实际运行代码时,才会被发现。所以,良好的测试变得更加重要。

2、代码的可读性

对于新手或者不熟悉代码库的开发者来说,鸭子类型在一定程度上会导致代码可读性的降低。所以,适当的注释和文档说明,也变得更加重要了。

总结

本文重点介绍了“鸭子类型”背后的核心理念,专注于行为而非类型本身。同时,对比了Java和Python这两种语言所代表的类型系统的差别,尤其在多态实现上的差异。尽管“鸭子类型”赋予了Python极大的灵活性和简洁性,但是,还是需要注意这些有点背后潜在的风险。

感谢您的拨冗阅读,希望对您有所帮助。

0 阅读:2

南宫理的日志录

简介:深耕IT科技,探索技术与人文的交集