引述
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限
的。而且,创建一个包含 100 万个元素的列表,不仅占用很大的存储空间,如果我们仅仅
需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推
算出后续的元素呢?这样就不必创建完整的 list,从而节省大量的空间。在 Python 中,
这种一边循环一边计算的机制,称为生成器(Generator)。
1.列表生成器改写
要创建一个 generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[ ] 改成
() ,就创建了一个 generator
例:判断2~num之间有多少个质数
def isPrime(num):
for i in range(2, num):
if num % i == 0:
return False
else:
return True
##列表生成式:
primeLi = [i for i in range(1,1000) if isPrime(i)]
print(primeLi)
##生成器:通过列表生成式改写. 一边循环, 一边计算。
primeLi = (i for i in range(2,1000) if isPrime(i))
##如果要一个一个打印出来,可以通过 generator 的 next() 方法
print(next(primeLi))
##将生成器执行完
from collections import Iterable
for i in primeLi:
print(i)
##判断是否可以for循环
print(isinstance(primeLi,Iterable))
2.yield方法
当函数中包含yield关键字,返回值是一个生成器, 如果要执行函数内容.需要调用next方法,
或者for循环.
运行过程: 当执行next方法时, 遇到yield程序停止, 直到执行下一次next方法时,
从上一次停止的yield处继续执行,遇到yield停止运行.
return: 遇到return函数执行结束;
例:实现斐波那契数列
斐波纳契数列以如下被以递推的方法定义:F(1)=1,F(2)=1,F(n)=F(n-1)+F(n-2)(n>=2,
n∈N*)
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,
4181,6765,10946,17711,28657,46368........
def fib(num):
#num为生成的数量
a = 0
b = 1
count = 0
while count < num:
yield b
a, b = b, a+b
count += 1
res = fib(100)
print(next(res))
生成器: 如果函数中有yield, 那么这个函数的返回值就是一个生成器。
生成器fib()执行的过程分析:
执行语句 f = fab(100) 时,并不会马上执行 fib() 函数的代码块,而是首先返回一个 iterable 对象(即生成器)!
在 for 循环语句执行时或者next(),才会执行 fib() 函数的代码块。
执行到语句 yield b 时,fib() 函数会返回一个迭代值,直到下次迭代前,
程序会回到 yield b 的下一条语句继续执行,然后再次回到 for 循环,如此迭代直到结束。
看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
由此可以看出,生成器通过关键字 yield 不断的将迭代器返回到内存进行处理,而不会一次性的将对象全部放入内存,
从而节省内存空间。
通过生成器创建的迷你机器人
生成器可以使用的方法:
- next(g)
- g.send(''), 给生成器传递值;
给yield所在位置发送一个数据, 直到遇到下一个yield停止.
def chat_robot():
res = ''
while True:
receive = yield res
if 'age' in receive:
res = '你猜'
elif 'hello' in receive:
res = '你好鸭'
elif 'name' in receive:
res = 'My name is villa'
elif 'sex' in receive:
res = "I'm a boy?"
else :
res = "I don't know what you say"
def main():
Robot = chat_robot()
next(Robot)
while True:
send_data = input("Messi>>:")
if send_data == 'q' or send_data == 'bye':
print("不聊了,我也撤了......")
break
print(Robot.send(send_data)) ##send_data给Robot传值
main()
运行结果: