迭代器
首先我们来说一下迭代的含义:把数据从容器中一个接一个地取出来就叫做迭代。
比如我们用for循环遍历字符串、列表、元组、字典、集合等时 实际上就是迭代地从中取出数据。这些容器都有一个共同的特性——可迭代。
那么python中到底哪些数据类型是可迭代的呢?
如果用函数dir()来查看字符串、列表、元组、集合、字典等你会发现所有这些数据类型都具有一个共同的内置方法__iter__,他们都满足可迭代协议,只要含有__iter__方法,那么它就是可迭代的。
而__iter__方法的作用就是返回一个迭代器对象,这个迭代器对象具有内置方法__next__,python通过调用__next__方法才实现了一个一个地取处数据。
我们来举个例子:
__iter__方法的作用就是返回一个迭代器,而迭代器具有__next__方法,最后python通过next方法把数据从迭代器中一个一个地取出来。
实际上 for循环就是完成了这两个步骤,先是把可迭代的对象通过__iter__方法返回一个迭代器,然后再用__next__方法把数据一个一个地取出来。
我们只要记住:凡是具有__iter__方法的都是可迭代的,凡是同时具有__iter__和__next__方法的就是迭代器生成器
虽然可以通过调用__iter__方法来得到迭代器,但其实这种内置的方法并不是给我们用的,它是python自己去用的,多数时候我们需要创建特定的迭代器,这时候我们只能自己去写代码,而我们自己写的这个能实现迭代器功能的代码就叫做生成器。
生成器是创建迭代器的简单而强大的工具。它写起来就像是正规的函数,需要返回数据的时候使用 yield 语句。每次 next() 被调用时,生成器回到它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)。
只要含有yield关键字的函数都是生成器函数。
由上例我们可以看出yield语句具有记忆功能,它记忆语句最后一次执行的位置和所有的数据值,当调用__next__()方法时 会执行函数g()内部的代码,当执行到yield n 时 函数g()就会返回一个迭代值n,下次调用__next__()方法时从yield n 下一条语句执行。
一个带有 yield 的函数就是一个 生成器函数,和普通函数不同,直接调用生成器函数不会执行任何函数代码,直到对其返回的生成器调用__next__()(在 for 循环中会自动调用)才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。
yield语句是一个表达式,它也可以进行赋值操作,也就是yield 不仅能把它后面的值作为迭代结果返回出去,而且还能把整个yield表达式的结果赋值给变量,但是要注意:yield表达式的值默认是None,也就是说可以把None赋值给变量,见下面的例子:
显然把一个None赋值给变量毫无意义,这里就引出了另一个调用生成器的方法——send(),与__next__方法不同的是send()方法可以传入一个参数给上一个yield表达式的值,记住是上一个yield,这意味着使用send时要先使用一次__next__(或者next())方法,我们还用刚才的例子,但是这次我们使用send来调用生成器)
不要迷糊,send和next基本功能一样,调用后都会使生成器函数内部的代码运行到下一个yield表达式处,唯一的区别就是:send在代码运行之前 会把一个参数传递给当前yield表达式(如果你从代码运行结束时的角度看那就是传递给上一个yield,因为代码会向下运行的。)并且可以作为结果直接赋值给其他变量。
欢迎关注我的公众号,谢谢!
领取专属 10元无门槛券
私享最新 技术干货