在创建列表的时候,存储的内容和大小已经固定,若创建的列表包含大量的元素,则会占据很大的存储空间,而且若只需要访问列表的前几个元素,则会造成较大的资源浪费。而使用生成器generator
即可避免这样的问题,generator
是根据已经写好的逻辑,动态循环创建的。
1.第一种创建方法,把列表解析的符号[]
换成()
,如下
代码:
a = [n for n in range(5)] # 返回的是list,可直接输出存储的数据
b = (n for n in range(5)) # 返回的是个generator,不能直接输出数据
print(a)
print(b)
结果:
[0, 1, 2, 3, 4]
at 0x0000000001131360>
1.1 获取generator存储的数据,可以用next()
方法,例如
代码:
b = (n for n in range(5))
print(next(b)) # 输出3次
print(next(b))
print(next(b))
结果:
0
1
2
(注意:若next()
输出的次数大于生成器存储的元素个数,则会抛出StopIteration
错误)
1.2 查看generator存储的数据,每次都调用next()
太过于繁琐,建议用for...in...
循环,例如
代码:
b = (n for n in range(5))
for value in b:
print(value)
结果:
0
1
2
3
4
用for
循环调用,可以不用担心抛出StopIteration
错误
2.第二种创建方法,在函数定义中使用yield
关键字,则该函数即为生成器函数,如下
代码:
def Fibonacci(number):
n, a, b = 0, 0, 1
while n < number:
yield b # 使用yield关键字,将b存储到generator中
a, b = b, a + b # a = b , b = a + b
n += 1
return 'over' # 在生成器函数中的return,不返回信息,而是将值存储在抛出的StopIteration中,可通过捕获异常来获取
print([n for n in Fibonacci(8)]) # 使用列表解析,将结果存储到数组中,为了看着好看而已→_→
结果:
[1, 1, 2, 3, 5, 8, 13, 21]
普通函数和生成器函数的区别:
普通函数中遇到return
语句或者执行到函数末尾会自动返回,而在生成器函数中,return
是不返回的,而是在调用next()
函数之后开始执行,而在yield
处返回,下次在调用next()
则再上次停止的yield
处继续开始执行
2.1 通过try-except
语句来获取return
的返回值,如下
代码:
result = Fibonacci(8)
while True:
try:
x = next(result) # 其实for循环就是一次次的执行next()函数
except StopIteration as e:
print('返回值是:', e.value)
break
结果:
返回值是: over
e.g.
利用生成器函数,将杨辉三角的每一行数据存储到list中输出。
代码:
def YHtriangle(max): # 构造杨辉三角的逻辑 max>2时,每个数都等于上一行同一位置的数+这个位置前一位置的数
n, L = 0, [1]
while n < max:
yield L # 此处将L列表存储到生成器中
L.append(0) # 存储后,在列表末尾添加0,为了下一行计算数据
L = [L[i - 1] + L[i] for i in range(len(L))] # 注意是range(len(L)),i-1=-1,每次取值都是上一句添加的0,
n += 1
def getYHtriangle(num): # 输出数据
for n in YHtriangle(num):
print(n)
getYHtriangle(4) # 调用函数
结果:
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
在笔记(3)中记过,可使用collections
模块的Iterable
类型来判断是否可被for
循环,补充,生成器generator或者是生成器函数也是可迭代对象Iterable
。
可以被next()
函数调用,并且不断返回下一个值的对象,叫做迭代器Iterator
同样可以使用isinstance()
函数来判断是否是迭代器(需要先导入Iterable
)
代码:
from collections import Iterator
print(isinstance(123, Iterator)) # 不是可迭代对象Iterable,也不是迭代器Iterator
print(isinstance('abc', Iterator)) # 字符串,列表,字典虽然可迭代Iterable,但不是迭代器Iterator
print(isinstance(['a', 'b'], Iterator))
print(isinstance(('a', 3), Iterator))
print(isinstance((n for n in range(5)), Iterator)) # 只有生成器是一个迭代器
结果:
False
False
False
False
True
字符串,列表,字典虽然只是可迭代,不是迭代器,但是可以通过函数iter()
获取一个迭代器Iterator
,例如。
代码:
from collections import Iterator
L = [1, 2, 3, 4]
print(isinstance(L, Iterator))
print(isinstance(iter(L), Iterator))
结果:
False
True