- 对列表生成式,可以生成一个列表,可是它所占优的内存是有限的,如果想要保存1万,10万,100万甚至更多数据时,用列表生成式就不太现实了。不仅造成空间的浪费,而且对后面不会用到的数据就浪费掉了。
- 生成器与列表生成式在写法上的区别是将
[]
改成()
- 条件是它的内部元素是可以根据某种算法推算而出,它的特点是一边循环一遍计算.
l=[x*x for x in range(10)]
print(l)
r=(x*x for x in range(10))
print(r)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object at 0x000002000ECD2E40>
- 对列表生成式来,可以将其中的元素一个个打印出来,那么对于生成器呢?同样地,也可以将其值一个个输出
next()
- 可以通过next()函数获得生成器的下一个返回值
r=(x*x for x in range(10))
print(next(r))
print(next(r))
print(next(r))
print(next(r))
print(next(r))
print(next(r))
print(next(r))
print(next(r))
print(next(r))
print(next(r))
0
1
4
9
16
25
36
49
64
81
- 需要注意的是,如果计算到最后一个元素,下一次无元素输出时,会抛出StopIteration 的异常
for循环
- 不断调⽤ next() 实在是太繁琐了,虽然是点一次出现一次,但正确的⽅法是使⽤ for 循环,因为⽣成器也是可迭代对象
- 判断是否是可迭代对象可以使用Python的内置函数
r=(x*x for x in range(10))
from collections.abc import Iterable
print(isinstance(r,Iterable))
True
- 创建一个生成器后,用for循环来迭代,并且不用担心StopIteration 异常
r=(x*x for x in range(10))
for rr in r:
print(rr)
0
1
4
9
16
25
36
49
64
81
next()
r=(x*x for x in range(10))
print(r.__next__())
send()
- send()第一次调用时里面的参数要为空,随后的不返回空
r=(x*x for x in range(10))
print(r.send(None))
print(r.send(''))
0
1
yield
- 如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:1, 1, 2, 3, 5, 8, 13, 21, 34, …
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(times):
a,b=0,1
n=0
while(n<times):
print(b)
a,b=b,a+b
n+=1
#调用函数
print(fib(5))
1
1
2
3
5
None
- 仔细观察,可以看出,fib_a函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield(b)就可以了
def fib(times):
a,b=0,1
n=0
while(n<times):
yield(b)
a,b=b,a+b
n+=1
#调用函数
print(fib(5))
- 对其进行输出也同样可以使用上述的4种方法,但一般地很少会使用next(),–next–(),send(),使用for循环会迭代会更便捷
def fib(times):
a,b=0,1
n=0
while(n<times):
yield(b)
a,b=b,a+b
n+=1
#调用函数
for r in fib(5):
print(r)
1
1
2
3
5