生成器
在循环的过程中不断推算出后续的元素,用以节省空间,这种一边循环一边计算的机制,成为生成器:generator,带 yield!
方法一:把列表生成式的[]改成()
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000021F20CDF270>
next()函数 获得 generator的下一个返回值
比如next(g)
,每次计算下一个元素的值,直到没有 下一个元素时抛出stopiteration的错误。
但用 next()太麻烦了,基本不用,都是用for循环
>>> g = (x * x for x in range(10))
>>> for n in g:
... print(n)
斐波拉契数列就适合用函数打印
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n+1
return 'done'
f = fib(5)
print(f)
这样拿不到generator的return语句的返回值,如果想要拿到包含在stopiteration的 value 中,用try捕获:
while True:
try:
x = next(g)
print('g:', x)
except StopIteration as e:
print('Generator return value:', e.value)
break
杨辉三角
def triangles():
yield [1] #第一行
yield [1,1] #第二行
res = [[1],[1,1]] #结果集
n = 2 #当前行数
while n:
temp = [] #临时list
temp.insert(0,res[n-1][0]) #前一行 的 第一个数
temp.append(res[n-1][-1]) #前一行最后一个数
i = 1 #i从1开始
while i < n: #i小于n当前行-1
temp.insert(i, res[n-1][i-1] + res[n-1][i]) #把中间部分的数给填满,填的是上一行的两个数相加
i += 1
res.append(temp) #每完成一行,加入到结果集里面去
n += 1 #当前行数加一
yield temp #暂停一次
#调用
def main():
n = 0
results = []
for t in triangles():
print(t)
results.append(t)
n = n + 1
if n == 10:
break
if results == [
[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
[1, 4, 6, 4, 1],
[1, 5, 10, 10, 5, 1],
[1, 6, 15, 20, 15, 6, 1],
[1, 7, 21, 35, 35, 21, 7, 1],
[1, 8, 28, 56, 70, 56, 28, 8, 1],
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
]:
print('测试通过!')
else:
print('测试失败!')
print(results)
main()
迭代器
可直接 用于for 循环的对象统称为可迭代对象,用 isinstance()判断 对象是否可迭代
例如:
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
可以被next()函数调用并不断返回下一个值的对象称为迭代器:iterator
可以用isinstance()判断一个对象是否是iterator对象:
>>> from collections.abc import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是iterator迭代器对象,但list、dict、str 虽然是iterable可迭代对象,却不是iterator迭代器。
把list、dict、str等Iterable强类型转换变成Iterator可以使用iter()函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
iterator 对象可以被next()函数调用并不断返回下一个数据,我们不能提前知道序列的长度,只能每次next()按需计算下一个数据。所以这是惰性计算。它可以表示一个无限大的数据流,如全体自然数,而list就不行。
总结:
可作用与for循环的都是iterable可迭代对象。
可作用于next()的都是iterator迭代器,表示惰性计算的序列。
集合数据类型如list、dict、str等可通过iter()强类型转换成迭代器对象