一、迭代器/生成器基本概念
1.1 什么是迭代器
迭代器(Iterator)
是同时实现__iter__() 与 __next__()
方法的对象。
1.2 什么是生成器
Python 中,提供了两种 生成器(Generator)
,一种是生成器函数
,另一种是生成器表达式
。
- 生成器函数:包含yeild的函数称为生成器函数
- 生成器表达式:与列表推导式类似,区别是使用()进行包裹 例:(i for i in range(10))
二、可迭代对象/迭代器
2.1 可迭代对象
可以直接作用于for循环的对象称为可迭代对象,可迭代对象主要分两类
- 一类是集合数据类型和迭代器,如
list
、tuple
、dict
、set
、str 和实现了__next__方法的类对象
; - 一类是
generator
,包括生成器和带yield
的generator function。
可以使用isinstance()来判断一个对象是否为可迭代对象
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
2.2 迭代器
Iterator:任何实现了 __next__ 方法 (python2 是 next)的对象都可以称为迭代器
可以使用isinstance()判断一个对象是否是Iterator对象:
>>> from typing import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是 Iterator(迭代器),但 list,tuple,dict,str,set 等虽然是Iterabel(可迭代对象),但不是Iterator(迭代器)
2.3 通过iter()方法把可迭代对象转换成迭代器
>>> from typing import Iterator
>>> str_iterator = iter("duozan")
>>> isinstance(str_iterator, Iterator)
True
>>> next(str_iterator)
d
问: 为什么 list,tuple,dict不是迭代器呢?
答: 因为在Python里面 迭代器代表的是一个数据流,迭代器对象可以调用next()方法返回下一个值,而list,tuple,dict无法调用next()方法返回下一个值。(本质为list,tuple,dict只有__iter__魔法方法,没有实现__next__魔法方法)
2.4 创建迭代器
通过实现__iter__() 和 __next__()方法实现一个迭代器
from typing import Iterator
class Fib:
def __init__(self, n):
self.prev = 1
self.cur = 2
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.n > 0:
value = self.cur
self.cur = self.cur + self.prev
self.prev = value
self.n -= 1
return value
else:
raise StopIteration()
f = Fib(10) //f 是一个迭代器
print(type(f),isinstance(f,Iterator))
print([i for i in f])
输出结果:
可以看到通过Fib类创建的对象是一个迭代器,可以用于循环操作
2.5 迭代器和列表的区别
它与列表的区别在于,构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。比如列表含有中一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素(按需调用 call by need 的方式,本质上 for 循环就是不断地调用迭代器的next方法)。
三、生成器表达式/生成器函数
3.1 通过列表生成式创建生成器
我们可以将列表生成式的中括号改成小括号就创建了一个生成器
list = [i for i in range(10)]
print(type(list)) # <class 'list'>
gen = (i for i in range(10))
print(type(gen)) # <class 'generator'>
3.2 通过函数创建生成器
带有yield的函数称为函数生成器
下面通过代码实现一个斐波那契数列(除第1个,第2个数外,其他的数都是前两个数相加) eg: 1, 2, 3, 5, 8, 13, 21, 34, 55, …
斐波那契数列代码:
# 实现100以内的斐波那契数
def fib(max):
a, b = 1, 2
n = 0 # 斐波那契数
print(str(a) + "\n" + str(b))
while n < max:
n = a + b
a = b #把b的旧值传给a
b = n #把相加之后的值传给新的b值
yield n # 程序走到这里就会暂停下来,返回n到函数外,等下一次调用next()的时候继续执行
for i in fib(100):
print(i)
运行结果:
1
2
3
5
8
13
21
34
55
89
144
这里非常有必要说一下带有yeild 关键字的生成器函数的执行流程,当调用一次next()的时候,生成器就会执行,碰到yield会先把值返回给外部(这里返回到的其实是i,然后print(i)打印的就是相加之后的值),当再次调用的时候,生成器会从上次中断的地方继续执行。
3.3 取出生成器里面的元素
1.通过调用next()方法取出
gen = (i for i in range(10))
gen.next()
2.通过使用for循环取出
gen = (i for i in range(10))
for i in gen:
print(i)
四、可迭代对象、迭代器、生成器小结
可迭代对象:实现了__iter__魔法方法 ,通过isinstance()判断是否为可迭代对象
迭代器:实现了__iter__ 和 __next__魔法方法
生成器: Python中含有两种生成器,生成器函数和生成器表达式
- 生成器函数:包含yeild的函数称为生成器函数
- 生成器表达式:与列表推导式类似,区别是使用()进行包裹 例:(i for i in range(10))
参考链接: