Python进阶-魔术方法(2)


3楼猫 发布时间:2024-08-13 00:55:06 作者:赢赢赢赢麻 Language

前言

前篇:

魔术方法(1):使用__str__与__repr__进行字符串操作

正文

魔术方法(2):使用__iter__与__next__实现可迭代

for循环可能是我们最熟悉的循环操作,但是你是否思考过,for循环内部做了些什么?它怎么知道什么时候停止循环?又是如何保证元素的遍历不会出错?

突然讲原理可能难以理解,先仔细观察下列代码和运行结果,认真分析一下打印的先后情况

Python进阶-魔术方法(2)-第0张

一个基于魔术方法实现的平方迭代器

Python进阶-魔术方法(2)-第1张

运行结果

在开始讲解之前,我们先补充几个知识点:

Python进阶-魔术方法(2)-第2张

专业术语的定义

  1. 可迭代对象:实现了__iter__方法,也就是可以使用for循环的对象

  2. 迭代器:如果一个可迭代对象里面也实现了__next__方法,那么这就是一个迭代器,也就是可以使用next()函数的对象

  3. 生成器:一种特殊的迭代器,自动实现了__iter____next__方法,也就是调用包含yield的函数所返回的对象(这种用法后面会在高级语法中讲解)

顺带一提,Python的三大基本序列类型就是list,tuple和range,怎么样,没想到吧,range的位格这么高,这可是官方文档(点击查看)自己说的

--------分割--------

接下来让我们逐步分析上述代码:

  1. 当我们对一个对象使用for i in XXX的时候,在这一步就会调用该对象的__iter__方法。因为返回的对象会交给for循环处理,所以通常我们会返回的其实就是对象本身即return self

  2. 在接下来每次读取值的时候,就会调用对象的__next__方法来得到下一个值,当返回的是停止信号(即StopIteration异常)时,读取结束,这也是为什么会多打印出一个__next__

也就是说使用__iter__来返回一个东西交给for循环,而__next__来逐步获得下一个值,直到抛出StopIteration

请务必理解上述执行过程,然后让我们用于实践

--------分割--------

假如有一个班级类,里面保存了很多学生的姓名,基本代码如下

Python进阶-魔术方法(2)-第3张

一个简单的教室类,用来保存学生姓名

如果我们希望遍历这些学生信息,你也许会使用

for student in classroom.students:

但是我个人来说并不喜欢这样,这并不优雅,而且暴露变量的引用往往意味着危险,外部的改变随时会改变对象内部的状态:

my_student = classroom.students

my_student.pop()

print(classroom.students)

当我将对象classroom的学生列表引用暴露出去,再使用这个引用弹出一个元素,对象内部的学生列表也发生了变化,这正是需要警惕的地方(谁说python没指针.doge)

现在我们来给Classroom类实现一个迭代属性,让我们可以对教室进行for循环!

Python进阶-魔术方法(2)-第3张

可迭代的教室类

Python进阶-魔术方法(2)-第3张

运行结果

这里有一个取巧的方法,不同于上面所说的“__iter__通常返回对象本身”,这里我们完全可以将遍历委托给students列表来实现,我们也不需要关心__next__的返回内容和跳出判断。


© 2022 3楼猫 下载APP 站点地图 广告合作:asmrly666@gmail.com