1为什么要用生成器
a=[x2 for x in rang(10)] 表示使用rang(10) 中的数生成一个列表,列表中的 每一个元素都是 x2,
这样a的结果就是 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
但是如果我们 使用a=[x*2 for x in rang(110000)] 这里的range范围比较大,那么a重元素的数量就会非常多,占用很大的内存空间。
我们有这样一种需求: 每次从a中取出一个元素,但是什么时候取是不知道的,所以我们希望等到取元素的时候再计算a中的下一个元素,也就是我们保存生成a 列表的 算法范式 (x*2),这样a就会占用很小的内存空间。这就是生成器 要解决的问题。
b=(x*2 for x in range(100))
print next(b)
print next(b)
print next(b)
输出:
0
2
4
上面(x*2 for x in range(100)) 就是一个生成器,将这个生成器赋值给b引用,通过next方法可以获取生成器中的 下一个元素
2创建生成器
1,创建生成器的第一种方式,将列表的[] 改为(), a=(x2 for x in range(10)).
注意区别 a=[x2 for x in range(10)] 这个中括号称为列表推导式, 其特点是立即生成列表中的元素。
而上面的a=(x*2 for x in range(10)). 这里返回的a是一个生成器。
- 带有yield的方法 被调用后会返回一个生成器对象。
def createNum():
print "createNum start"
i=0
a=1
b=1
while i<5:
a,b=b,a+b
print a,b
i=i+1
yield b
print "createNum stop"
generator=createNum()
print generator #<generator object createNum at 0x0000000003133900>
print next(generator)
print next(generator)
这里有一个问题, 调用含有yield方法 返回一个生成器对象,然后我们可以使用next(generator)获取下一个值,这里的这个值是哪个变量的值,是如何生成的? 这取决于yield 语句中 包含的 表达式的值。
当我们调用next(generator) 的时候,生成器会自动运行到yield语句的位置,并返回yield语句中表达式的值 。
这里包含了这两个操作。
另一个问题,上面显示 while循环将会循环5次,5次之后就退出了while,也就是说next(generator )最多调用五次,如果调用了六次,那么第六次执行next(generator)的时候将会出现错误stopIteration
3从生成器中获取元素
1,next(generator)
2,generator.next()
3 使用for循环遍历生成器对象
for x in generator
4 send 和next
def testSend():
i=0
while i<5:
temp=yield i
print (temp)
i=+1
generatorSend=testSend()
print next(generatorSend)
print(next(generatorSend))
输出结果:
0
None
1
当第一次运行next的时候,程序会执行到testSend方法的yield语句的地方,然后程序被挂起,此时返回i的值是0,因此next方法的返回值是0.
当第二次运行next的时候 会首先置信print(temp),然后挂起在yield语句的地方,并输出print(next(generatorSend))
但是为什么 print(temp)会输出 none?? 按照我的理解temp的值为第一次执行yield i的返回值,也就是i=temp=0。
书中给出的解释如下:
image.png
这里有一个问题, temp=yield i 和 yield i的区别,前者是yield表达式,后者是yield语句;表达式总是有值的,而语句不一定有值。
在本示例中yield是作为一个表达式使用的,这个表达式的值是yield方法返回的一个值,而这个值是通过外部send方法发送的值,所以temp的值就是send方法发送的值。
简单来说 next得到的值是yield 后面他的表达式 计算得到的值。
yield i 整体的值是send方法发送的值,temp表示将yield i整体的值赋值给temp,而不是将yield语句中内部子表达式的值赋给temp。
5 send 方法
def testSend():
i=0
while i<5:
temp=yield i
print (temp)
i=i+1
generatorSend=testSend()
print next(generatorSend)
print generatorSend.send("xx")
print(next(generatorSend)))
输出结果:
0
xx
None
2
从这个例子中我们可以看出send方法 有两个作用
(1)将send方法的参数作为 yield i 表达式的整体结果赋值给temp
(2)可以使得程序继续从yield挂起的地方继续往下运行,直至再次遇到yield挂起,在这一点上和next方法相同
另外补充两点
(3) send方法之前之前,程序挂起在yield语句的地方,send 方法的参数作为本次yield i整体的结果。也就说send方法只表示本次yield i整体的结果,而不影响后续 执行yield i 整体的结果。这也要求 send之前需要 先将程序挂起在yield处
(4)send(None)与next ()两个函数作用相同。
网友评论