这是我参与11月更文挑战的13天,活动详情查看:2021最后一次更文挑战。
生成器(generator
)
列表所有数据都在内存中,如果有海量数据的话会非常消耗内存。
例如,我们仅仅需要访问前面几个元素,但后面绝大多元素占用的内存就会浪费了。
那么生成器就是在循环的过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,从而节省大量的空间。
总而言之,就是当我们想要使用庞大数据,又想让它占用的空间少,那就使用生成器。
如何创建生成器
生成器表达式
生成器表达式
来源于迭代和列表解析的组合,生成器和列表解析类似,但是它使用()
而不是[]
:
g = (x for x in range(5))
print(g) # generator object
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# 超出报错
print(next(g))
for i in g:
print(i)
复制代码
生成器
当一个函数中包含yield
关键字,那么这个函数就不再是一个普通的函数,而是一个generator
。 生成器
表达式来源于迭代和列表解析的组合,生成器
和列表解析类似,但是它使用()
而不是[]
。 调用函数就是创建了一个生成器对象。其工作原理就是通过重复调用next()
或者__next__()
方法,直到捕获一个异常:
def yieldtest(number):
n = 0
# li = []
while n<number:
# li.append(n)
yield n
n+=1
res = yieldtest(20)
print(res) # generator object
print(next(res)) # 0
print(next(res)) # 1
print(next(res)) # 2
复制代码
⚠️注意:
yield
返回一个值,并且记住这个返回值的位置,下次遇到next()
调用时,代码从yield
的下一条语句开始执行。与return
的差别是,return
也是返回一个值,但是直接结束函数。
例如,实现斐波那契数列。除第一个和第二个数外,任何一个数都可以由前两个相加得到:1,1,2,3,5,8,12,21,34.....
def createNums():
print("-----func start-----")
a,b = 0,1
for i in range(5):
# print(b)
print("--1--")
yield b
print("--2--")
a,b = b,a+b
print("--3--")
print("-----func end-----")
g = createNums()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
复制代码
send()
send()
和next()
一样,都能让生成器继续往下走一步(遇到yield
返回),但send()
能传一个值,这个值作为yield
表达式整体的结果:
def test():
a1 = yield "hello"
print("---1---")
yield a1
res = test()
print(next(res)) # "hello"
print(res.send("world")) # "world"
复制代码
也就是说,通过send
方法可以强行修改上一个yield
表达式值。
比如函数中有一个yield
赋值:
a1 = yield "hello"
复制代码
- 第一次迭代到这里会返回
"hello"
,但是a1
还没进行赋值; - 第二次迭代时,使用
.send("world")
; - 那么,就是相当于强行修改
yield "hello"
表达式的值为"world"
; - 所以
yield a1
结果为"world"
。