python——列表生成式、生成器
一、列表生成式
根据表达式,一次性生成一个列表。缺点:占用内存空间;
[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))
如需转载,请注明出处,否则本人会追究法律责任!