一、生成器

2.1 定义

在python中,一边循环一边计算的机制,称为生成器(generator)。之所以需要生成器,是因为其本身具备的优秀性质:

  • 节约内存,python在使用生成器时对延迟操作提供了支持。所谓延迟,是指在需要的时候才产生结果,而不是立即产生结果。这样在需要的时候才去调用结果,而不是将结果提前存储起来要节约内存。比如以列表的形式存放较大数据将会占用不少内存,使用生成器来调取数据结果而不是列表来处理数据,因为这样可以节约内存。
  • 迭代到下一次的调用时,所使用的参数都是上一次所保留下的。

2.2 创建生成器

2.2.1 生成器表达式

生成器表达式与列表推导式在形式上很类似,只是生成器表达式使用括号”()”来构建,使用next()来调用:

  1. # 列表推导式:会一次性返回所有结果
  2. t = [i**2 for i in range(5)]
  3. # 生成器表达式:每调用一次next()返回一个,直至it为空
  4. it = (i**2 for i in range(5))
  5. next(it)

2.2.2 生成器函数

生成器函数使用yield返回值,不是return。yield语句每次返回一个结果,并挂起函数的状态,以便下次从它离开的地方继续执行。

  1. def odd():
  2. n=1
  3. while True:
  4. yield n
  5. n+=2
  6. odd_num=odd() # 调用生成器函数,odd_num为生成器对象:<generator object odd at 0x1098e5750>
  7. count=0
  8. for o in odd_num:
  9. if count >=5:
  10. break
  11. print(o)
  12. count += 1

2.2.3 next()与send()方法

我们先看一个生成斐波纳契数列例子:

  1. def fib(times):
  2. n = 0
  3. a,b = 0,1
  4. while n < times:
  5. yield b
  6. a,b = b,a + b
  7. n += 1
  8. return "done"
  9. f = fib(5)
  10. for x in f:
  11. print(x)

next() 方法和next的作用是一样的,f.next() 和 next(f) 是作用是一样的。如下所示

  1. def fib(times):
  2. n=0
  3. a,b=0,1
  4. while n < times:
  5. yield b
  6. a,b=b,a+b
  7. n+=1
  8. f = fib(5)
  9. for i in range(5):
  10. print(f.__next__())

再来看看send()的作用:

  1. def fib(times):
  2. n = 0
  3. a,b = 0,1
  4. while n < times:
  5. temp = yield b
  6. print(temp)
  7. a,b = b,a+b
  8. n += 1
  9. f = fib(5)
  10. print(f.__next__())
  11. print(f.send("haha"))
  12. print(f.send("lalala"))

其结果为:

  1. 1
  2. haha
  3. 1
  4. lalala
  5. 2
  6. [Finished in 0.3s]