做者:清菡
博客:oschina、云+社区、知乎等各大平台都有。微信
因为微信公众号推送改成了信息流的形式,防止走丢,请给加个星标 ⭐,你就能够第一时间接收到本公众号的推送!
1、迭代器函数
2、生成器性能
一种是包含iter
方法的,另外一种是包含getitem
方法的(好比str
对象就没有iter
方法,可是同样可以迭代),只要对象中包含了这两种方法的任意一种,那么这个对象就能够进行迭代操做,也就是实现了迭代协议。测试
生成器是迭代器的一种。迭代器的范围比生成器更广。只要能够经过next()
,从里面一个一个往外面取值,都被称为迭代器。编码
关于要建立一个迭代器对象,那么内部要实现一个迭代器的协议。spa
iter()
方法)。__next__
方法。__next__
方法返回了某个数值(固然通常状况下,咱们须要的是返回这个对象的特定的数字,而且按照必定的顺序进行依次返回)。__next__
方法须要在值取完的时候,抛出stopiteration
的错误信息。有个东西须要区分,一个是迭代器,一个是可迭代对象。code
只要内部实现了迭代协议的就是一个可迭代对象(可迭代对象能够进行相关的迭代操做,好比for
循环,map
函数等)。对象
能够用 for 循环进行遍历的,那么都是可迭代对象。可迭代对象不必定是迭代器,迭代器是在可迭代基础上,它内部要首先定义一个__next_
方法。blog
迭代器内部实现了一个__next_
方法,实现了这个方法以后,经过__next_
这个函数才能够对这个迭代器进行一个取值。rem
还有个iter()
方法,这个方法可将可迭代对象转换成一个迭代器。
yield
和return
是 2 个东西。yield
只是暂停那个生成器函数。yield
能够从生成器里面生成一个内容。
列表能够进行 for 循环,能够进行 for 循环遍历,它就是个可迭代对象。 列表是能够经过 for 循环遍历的,可是它不是迭代器。
迭代器是能够经过next()
进行取值的。
生成器也是迭代器,生成器是能够经过next()
去取值。那么,生成器它是迭代器的一种,是属于迭代器的。
你看,报错了:
# 列表 # 可迭代对象:能够for循环遍历的都是可迭代对象 li = [1,2,3,4] next(li) print(next(li))
提示:列表它不是一个迭代器。
不是个迭代器,不能经过这个去取值。要把一个可迭代对象转换成一个迭代器的话,经过iter()
这个函数把可迭代对象放进去,它可以返回一个迭代器。
你看,这样就能获取到了:
# 列表 # 可迭代对象:能够for循环遍历的都是可迭代对象 li = [1,2,3,4] li1 = iter(li) print(next(li1)) print(next(li1))
经过iter()
这个函数,来处理某个对象,它实际上至关于触发这个对象内部的一个__iter__
这个方法。
我们看看list()
的源码:
经过iter()
这个函数把对象li
传进去的时候,它会触发li
这个对象对应的__iter_
这个方法。
若是经过next()
去取值,把li1
这个对象传进去的时候,其实是触发这个对象的__next__
方法。
它的类里面只有这个__iter__
方法。
迭代器能够经过__next__
取值。迭代器内部实现了__next__
方法。
迭代器内部实现了 __iter__
方法以外,还实现了__next__
方法。
生成器是迭代器的一种。
迭代器是在可迭代对象的基础上实现了__iter_
方法。迭代器和生成器均可以支持迭代操做。
for 循环。
生成器是迭代器的一种。 刚才用起来的时候好像没有什么区别,打印下这个类型看看。
能够看到,它返回的是个列表迭代器对象:
这个是生成器对象:
li1 = iter(li)
这个是可迭代对象。而后经过iter()
转换成一个迭代器。
send()方法 | 发送数据 |
---|---|
close() 方法 | 关闭生成器 |
throw() 方法 | 使用的 throw 指令抛出错误 |
生成器是有send
这个方法的,迭代器是没有的。
例如,前面有个生成器叫作tu
:
# () 生成器表达式 tu = (i for i in range(1000))#生成器对象 print(tu)
tu
能够调用send()
这个方法,能够与生成器进行交互,可将数据传输到生成器里面。
举个栗子:
生成器是迭代器的一种。
例如定义了一个父类,再有个子类,父类建立出一个对象,子类建立出一个对象。子类有本身的方法。父类建立的出来的对象里面,确定没有子类对象里面的方法。 子类里面有的方法,父类里面没有。
迭代器就是“父类”。生成器就是“子类”。
def gen(): for i in range(1,5): yield i gen()
生成器运行的时候,调用函数gen()
,调用这个函数的时候,这个函数里面的代码不会直接运行。
代码修改为这样:
def gen(): for i in range(1,5): yield i g = gen() print(g)
只有经过next()
方法往生成器里面取值的时候,它才会从代码上面往下面运行。
这个send()
方法可将数据传到生成器里面。使用next()
,从生成器里面获取出一个值。若是使用send()
方法,它也可以获取出来一条数据。
def gen(): for i in range(1,5): se = yield i print(se) g = gen() print(next(g)) print(g.send(100))
send()
方法能够往生成器里面传入一个值。
经过send()
方法生成数据的时候,它也能够往里面发送一个 100 的值。
若是经过next()
去取值的话,这个yield
完毕后是没有返回内容的。
代码详解:
第一轮: 循环进来,经过next()
去取值生成了一个 1:
def gen(): for i in range(1,5): se = yield i print(se) g = gen() print(next(g))
第二轮: 经过print(g.send(100))
去发送值,而后打印:
def gen(): for i in range(1,5): se = yield i print('se的值:',se) g = gen() print(next(g)) print(g.send(100))
在第一轮结束以后,在yield
这里,yield
完毕就中止了。在第一轮yield
完以后,第二轮经过send()
传值进去,传到se
那里,打印出来 100。
而后再往上返回一个数据,又暂停,返回第二条数据就是个 2。
第三轮: 经过next()
再去生成一条元素,又触发了yield i
这个地方,这里释放了,日后面走,日后面走的话,可是没有放数据进来,这个时候se
是空的,打印出来的se
是空的。
而后再往上,生成一条元素到 3,而后又停在yield i
这个地方了,生成完元素,把这个值返回出去。
def gen(): for i in range(1,5): se = yield i print('se的值:',se) g = gen() print(next(g)) print(g.send(100)) print(next(g))
再次next()
或者send()
来触发它的时候,它会这样走:
注意: yield
接收不是存在i
中,这个yield
返回出来的i
是遍历出来的内容。
send()
发进去的,是yield i
这里运行完毕以后,当下一个send()
触发的时候,它把这个值发送到yield i
这里运行完毕以后的一个结果。
yield i
这里把这个i
返回出去,就停在这里不动了。send()
发送个数据进去,那么数据就发送到个yield i
这地方。
至关于yield i
这个地方返回的一个结果,也就是send()
发进去的内容,若是send()
不发进去内容,返回出来是个空的。
舒适提示:生成器<迭代器<可迭代对象
公众号 「清菡软件测试」 首发,更多原创文章:清菡软件测试 109+原创文章,欢迎关注、交流,禁止第三方擅自转载。