一、列表生成式
根据表达式,一次性生成一个列表。缺点:占用内存空间;
[x for x in range(10)] # 生成列表 [0,1,2,3,4,5,6,7,8,9]
[x*2 for x in range(10)] # 生成列表 [0,2,4,6,8,10,12,14,16,18]
二、迭代器Iterator
生成器都是迭代器,迭代器不一定是生成器。Iterator(迭代器),Iterable(可迭代对象)。满足两个条件即为迭代器:有iter方法;有next方法;
l=[1,2,3,4,5]
l.__iter__() # 根据列表l生成一个可迭代对象;等效于 iter(l),并且推荐使用iter()函数;
for循环内部做的三件事:
调用可迭代对象的iter方法返回一个迭代器对象;
不断调用迭代器对象的next方法;
处理stopIteration异常;
三、生成器Generator
一边循环一边计算的机制,称为生成器(Generator)。生成器本身就是一个可迭代对象。生成器其实就是一种特殊的迭代器。
列表生成式是生成一个列表;生成器是储存一个算法,每次调用时都会计算出下一个值。
生成器有两种生成方式:
1、 将列表生成式的 [ 改为 (
(x for x in range(10))
2、 yield
def foo():
print("in the func foo.")
return "foo"
foo() # 这里foo是一个函数。
def foo():
print("in the func foo.")
yield "foo"
foo() # 这里foo是一个函数,但是是一个生成器函数。foo()就是一个生成器对象
生成器调用
在python2中,生成器有个方法next,直接 generator.next()即可调用。
在python3中,这个方法被取消了,改为了next内置方法。不建议使用。代替的为 next函数。官方也建议这么做:使用next函数进行调用。
def foo2():
print("in the func foo.")
yield "111"
print("222 in the foo.")
yield 2
return 333 # 如果没有return,默认是 return None;当生成器调用溢出时,会抛出这个异常;
f=foo2() # 调用生成器函数foo2,生成一个生成器
next(f) # 第一次调用,打印 in the func foo.;返回 “111”
next(f) # 第二次调用,打印 222 in the foo. ;返回 2
next(f) # 报错 StopIteration ,因为生成器函数只有两个yield,所有生成器f只能取两个元素。当取第三个时,因为不存在,所有报异常。如上面有return,则返回异常: StopIteration 333
注:在上面例子中,不要这样调用: next(foo2());这样调用永远返回第一个元素,因为每次执行调用next(foo2())时,都是调用生成器函数,都重新生成一个生成器;故,切记千万不要在next()中写 foo2()形式;
生成器的函数send
生成器的send函数是用来给yield前面的变量传递一个值。但是如果第一次调用send方法前没有next调用,则send只能传递一个None。
def foo2():
print("in the func foo.")
pre_send=yield "111"
print(pre_send)
print("222 in the foo.")
yield 2
f=foo2()
f.send(None) # 等价于 next(f)
f.send('send for test') #这里相当于把 'send for test' 传递给了第一个yield;然后yield赋值给了pre_send变量。
利用生成器,生成一个斐波那契生成器:
def fib():
a = 0
b = 1
l = [0,1]
yield a
yield b
for i in range(11+1)[3:]:
a,b=b,a+b
result = b
l.append(result)
yield result
g=fib()
print(next(g))
print(next(g))