87、Python之鸭子类型:自定义容器,用起来像容器,它就是容器

南宫理的日志录 2024-11-12 08:02:09
引言

在其他编程语言中,如果要实现自定义一个容器类型,通常的做法是继承编程语言内置的容器类型,然后包装或者覆盖相应方法的实现。从类型上看,自定义的容器类型,首先必须是容器类型。

但是,在Python鸭子类型以及魔术方法的体系加持下,我们可以不继承任何容器类型,自定义一个类型,实现相关的魔术方法,从而让这个自定义的类型,像内置容器一样使用。而如果一个类型用起来像容器一样,那么它就是容器类型。

本文就来聊一下容器类型的相关魔术方法,以及如何自定义容器类型。

本文的内容有:

1、什么是容器类型

2、容器类型相关的魔术方法

3、自定义容器类型

什么是容器类型

在各种编程语言中,容器类型都是非常有用、非常核心的数据结构,在各种业务场景中,都有可能用到容器类型。

所谓容器类型(Container Types)是指能够包含其他对象的集合类型,它们可以存储多个元素,并提供访问和操作这些元素的方式。

在Python中,常见的容器类型有:列表(list)、元组(tuple)、字典(dict)、集合(set)等。这些内容我们在前面的文章中都已经有所介绍,感兴趣的可以自行查阅下历史文章。

典型的容器类型,通常会表现出以下几种行为(或者称之为操作、特性):

1、存储多个元素:容器可以存储多个任意类型的元素。

2、元素访问:容器类型通常提供访问其中包含的元素的方法,比如,可以通过索引访问列表中的元素,可以通过键值访问字典中的元素。

3、元素检查:容器类型通常支持成员资格的测试,比如使用in或者not in来判断元素是否存在于容器中。

容器类型相关的魔术方法

我们在Python中通过相关的操作符或者关键字操作容器类型时,其本质上是通过调用容器类型对应的魔术方法来实现的。接下来,简单列举一下容器类型中比较常用的容器操作相关的魔术方法。

1、获取容器的长度/容器中元素的个数

容器类型对象通过len()函数,可以获取容器对象中的元素个数,本质上是调用容器对象的__len__()方法。

2、获取容器对象中的元素

通过容器对象[key]的方式获取对象中的元素,本质上是通过调用容器对象的__getitem__()方法来实现的。

3、设置容器对象中的元素

通过容器对象[key] = value的形式设置容器中的元素,本质上是通过调用容器对象的__setitem__()方法来实现的。

4、删除容器对象中的元素

通过del 容器对象[key]的形式来删除容器对象中的元素,本质上是通过调用容器对象的__delitem__()方法来实现的。

5、元素检查操作

通过value in 容器对象,或者value not in 容器对象,来检查元素是否存在于容器对象中,本质上是通过调用内容起对象的__contains__()方法来实现的。

当然,还有其他扩展的魔术方法,这里就不再展开了。

自定义容器类型

通过上面内容的介绍,我们已经知晓了容器对象几个比较关键的行为,也知道了这些行为背后所对应的魔术方法。那么,我们要自定义一个容器类型就变得非常简单了。

只要自定义容器类型,并定义相应的魔术方法,让自定义的类型表现地像容器类型一样,那么我们自定义地这个类型,它就是容器类型。

接下来,通过代码实例来演示自定义容器类型的方法:

运行结果:

从运行结果中可以看到,Python的各种对容器类型的操作,确实是调用了对应的魔术方法。值得注意的一点是,for循环遍历容器对象时,调用了__getitem__()方法,只有2个元素,调用了3次__getitem__()方法。

需要说明的是,当我们将容器类型的相关魔术方法与迭代协议相关的魔术方法同时都定义时,可能会有不同的呈现,从而能看到更加完整的Python解释器关于魔术方法的调用顺序,这部分内容后面我们继续进行展开。

总结

本文简单介绍了容器类型,容器类型的主要行为,以及容器类型的各种行为背后,所对应的魔术方法。最后基于对这些知识的理解,进行了自定义容器类型的实现。

总结来说,要把鸭子类型的理念运用自如,可以分3步:

1、分析这个对象/类的典型的行为有哪些。

2、分析行为背后的实现,通常会有对应的魔术方法。

3、通过自定义类型并实现相应的魔术方法,从而让自定义类型表现出对应的行为。

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

0 阅读:0

南宫理的日志录

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