Python-可迭代对象、迭代器、生成器
关系
首先从概念上来说,生成器都是迭代器,迭代器都是可迭代对象。
从另一个角度,可迭代对象包含迭代器、序列(字符串、列表和元组)以及字典。
如果一个对象拥有__iter__
方法,其就是可迭代对象;再次基础上添加__next__
方法,就是迭代器。
可迭代对象
如何自定义可迭代对象?
首先定义一个普通类,利用iter()
方法调用,看会出现什么情况?
1 | class MyIterable: |
此时运行会输出TypeError: 'MyIterable' object is not iterable
,可知MyIterable
是不可迭代的。
在上面的基础上添加__iter__
方法
1 | class MyIterable: |
再次运行输出内容为<list_iterator object at 0x7f54747f6f70>
,说明iter(ex)
是一个list_iterator。
这里说一下__iter__
的返回值,__iter__
的返回值应该是一个迭代器,在实现上有两种方式:
- 若当前对象是一个迭代器,可以直接返回
self
; - 另一种情况是返回其他的一种迭代器。
1 | class MyIterable: |
迭代器
迭代器是一种特殊可迭代对象,可以在可迭代对象的基础上添加__next__
方法,可以使用内置函数next()
来获取下一个元素,当迭代完所有元素后,不可再次迭代,如果继续获取下一个元素,则抛出StopIteration
异常。
可以通过调用next()
函数判断对象是否为迭代器,如果可以使用next()
函数获取元素的对象,则一定为迭代器。
许多函数都能返回迭代器,例如enumerate
。
对于可迭代对象转为迭代器的方法主要有两种,一种就是通过添加__next__
方法实现,另一种就是利用iter()
函数将列表、元组等转为迭代器。
1 | # 自定义迭代器 |
生成器
生成器是一种特殊的迭代器,但是不需要手动写__iter__
和__next__
方法。
获取生成器对象有两种方法,一种是生成器表达式,另一种是生成器函数。
生成器表达式
将列表推导式的中括号改为小括号,它返回的是一个生成器对象而不是列表对象。
1 | example = (i for i in range(i)) |
生成器函数
对于生成器函数,是在函数体中没有return
关键字,而是采用yield
返回值。
1 | def foo(): |
yield
当函数体中存在yield
关键字时,便认为该函数为生成器函数,可以用过调用next
函数获取值。
当生成器遇到yield
时,便会暂停运行生成器,返回yield后面的值,保存当前状态,当再次调用生成器时,会从刚才暂停的地方继续执行,知道下一个yield
。
send
可以通过send
方法向函数体中传值,但第一必须有None
进行初始化。
1 | def foo(): |
输出为
1 | 1 |
通过exam.send(None)
初始化生成器,程序运行至yield 1
时,返回1;之后再用生成器的send
方法进入生成器内部,同时代入11,赋值给value。直到运行至yield value
,将value
值返回。