一、可迭代对象
可用for循环进行迭代的对象,字符串、列表、元组、集合、字典。但它们不是迭代器。
二、迭代器
列表可以通过iter转为迭代器,如下:
>>> x = [1, 2, 3]
>>> a = iter(x)
>>> b = iter(x)
>>> next(a)
1
>>> next(a)
2
>>> next(b)
1
>>> type(x)
<class 'list'>
>>> type(a)
<class 'list_iterator'>
>>> type(b)
<class 'list_iterator'>
在循环遍历自定义容器对象时,会使用python内置函数iter()调用遍历对象的__iter__()
获得一个迭代器,之后再循环对这个迭代器使用next()
调用迭代器对象的__next__()
。__iter__()
只会被调用一次,而__next__()
会被调用 n 次。
迭代器与列表的区别在于,构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。比如列表中含有一千万个整数,需要占超过100M的内存,而迭代器只需要几十个字节的空间。因为它并没有把所有元素装载到内存中,而是等到调用next()
方法的时候才返回该元素(按需调用 call by need 的方式,本质上 for 循环就是不断地调用迭代器的next()
方法)。
三、生成器
分为两种:生成器函数(用yield实现);生成器表达式,x = (x*x for x in range(10))。
普通函数用return
返回一个值,还有一种函数用yield
返回值,这种函数叫生成器函数。函数被调用时会返回一个生成器对象。生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅,它不需要像普通迭代器一样实现__iter__()
和__next__()
方法了,只需要一个yield
关键字。生成器一定是迭代器(反之不成立),因此任何生成器也是一种懒加载的模式生成值。
yield
就是return
返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始。next
方法和send
方法都可以返回下一个元素,区别在于send
可以传递参数给yield
表达式,这时传递的参数会作为yield表达式的值,而yield的参数是返回给调用者的值。
详情参见:https://zhuanlan.zhihu.com/p/341439647