生成器(generator)
定义
- 通过列表生成式,我们可以直接创建一个列表。但受到内存限制,容量肯定是有限。(创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费。)
- 所以如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。
- 在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator
1 只要把一个列表生成式的[]改成(),就创建了一个generator
- 一个一个打印出来,可以通过
next()
函数获得generator的下一个返回值
generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。 - 正确的方法是使用for循环,因为generator也是可迭代对象:
g = (x * x for x in range(4))
print(g)
#<generator object <genexpr> at 0x0000014E15F44E60>
print(next(g))
#0
print(next(g))
#1
#接着上边执行
for n in g:
print(n)
#4
#9
for n in (x * x for x in range(2)):
print(n)
#0
#1
2 函数定义中包含yield关键字
那么这个函数就不再是一个普通函数,而是一个generator:
普通函数和generator函数不同之处
- 普通函数和generator函数的执行流程不一样。
普通函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
generator函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。 - 普通函数和generator函数调用结果不一样
普通函数调用直接返回具体结果
generator函数的“调用”实际返回一个generator对象
<generator.......
def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
o = odd()
print(next(o))
print(next(o))
for p in odd():
print(p)
'''
step 1
1
step 1
1
step 2
3
step 3
5
'''
#-------------------------------------------------------------------------------------------------------------------------------
def start_requests():
for p in range(1,5):
url = f"https://seekingalpha.com/latest-articles?page={p}"
yield {"url": url}
g=start_requests()
print(next(g))
print(next(g))
print(next(g))
for p in start_requests():
print(p)
'''
{'url': 'https://seekingalpha.com/latest-articles?page=1'}
{'url': 'https://seekingalpha.com/latest-articles?page=2'}
{'url': 'https://seekingalpha.com/latest-articles?page=3'}
{'url': 'https://seekingalpha.com/latest-articles?page=1'}
{'url': 'https://seekingalpha.com/latest-articles?page=2'}
{'url': 'https://seekingalpha.com/latest-articles?page=3'}
{'url': 'https://seekingalpha.com/latest-articles?page=4'}
'''
迭代器(Iterator)
可以直接作用于for循环的数据类型有以下几种:
- 一类是集合数据类型,如list、tuple、dict、set、str等;
- 一类是generator,包括生成器和带yield的generator function。
定义
-
Iterable可迭代对象
:这些可以直接作用于for循环的对象统称为可迭代对象 -
Iterator迭代器
:不但可以作用于for循环,还可以被next()函数调用并不断返回下一个值的对象称为迭代器 - 凡是可作用于for循环的对象都是
Iterable
类型; - 凡是可作用于
next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列; - 集合数据类型如
list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
因为Python的Iterator对象表示的是一个数据流,
Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。
可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,
只不断通过next()实现按需计算下一个数据,所以Iterator计算是惰性,只在需要返回下一个数据时才会计算
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
from collections.abc import Iterator
a=isinstance((x for x in range(10)), Iterator)
print(a)
#True
b=isinstance(iter('abc'), Iterator)
print(b)
#True